Velocity Reviews > Why write putc(s.i16 & 0xff, fp);

# Why write putc(s.i16 & 0xff, fp);

Jorge Peixoto
Guest
Posts: n/a

 10-26-2007
In the answer to question 12.42 of the C FAQ, we have this code:

putc((unsigned)((s.i32 >> 24) & 0xff), fp);
putc((unsigned)((s.i32 >> 16) & 0xff), fp);
putc((unsigned)((s.i32 >> & 0xff), fp);
putc((unsigned)(s.i32 & 0xff), fp);

putc((s.i16 >> & 0xff, fp);
putc(s.i16 & 0xff, fp);

Why the & 0xff ? The putc function casts its argument to an unsigned
char, so anything but the 8 lower bits is automatically discarded. And
the code already assumes the a char is 8 bits.

CBFalconer
Guest
Posts: n/a

 10-26-2007
Jorge Peixoto wrote:
>
> In the answer to question 12.42 of the C FAQ, we have this code:
>
> putc((unsigned)((s.i32 >> 24) & 0xff), fp);
> putc((unsigned)((s.i32 >> 16) & 0xff), fp);
> putc((unsigned)((s.i32 >> & 0xff), fp);
> putc((unsigned)(s.i32 & 0xff), fp);
>
> putc((s.i16 >> & 0xff, fp);
> putc(s.i16 & 0xff, fp);
>
> Why the & 0xff ? The putc function casts its argument to an unsigned
> char, so anything but the 8 lower bits is automatically discarded. And
> the code already assumes the a char is 8 bits.

Where did you get the magic number 8 there? Bytes and chars can be
any size greater or equal to 8, given by CHAR_BIT in limits.h.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Jorge Peixoto
Guest
Posts: n/a

 10-26-2007
On Oct 26, 5:58 pm, CBFalconer <(E-Mail Removed)> wrote:
> Jorge Peixoto wrote:
>
> > In the answer to question 12.42 of the C FAQ, we have this code:

>
> > putc((unsigned)((s.i32 >> 24) & 0xff), fp);
> > putc((unsigned)((s.i32 >> 16) & 0xff), fp);
> > putc((unsigned)((s.i32 >> & 0xff), fp);
> > putc((unsigned)(s.i32 & 0xff), fp);

>
> > putc((s.i16 >> & 0xff, fp);
> > putc(s.i16 & 0xff, fp);

>
> > Why the & 0xff ? The putc function casts its argument to an unsigned
> > char, so anything but the 8 lower bits is automatically discarded. And
> > the code already assumes the a char is 8 bits.

>
> Where did you get the magic number 8 there? Bytes and chars can be
> any size greater or equal to 8, given by CHAR_BIT in limits.h

Yes, but this code (which is from the C FAQ) already assumes that char
is 8 bits. Read the answer to the question 12.42 of the FAQ.

pete
Guest
Posts: n/a

 10-26-2007
Jorge Peixoto wrote:
>
> In the answer to question 12.42 of the C FAQ, we have this code:
>
> putc((unsigned)((s.i32 >> 24) & 0xff), fp);
> putc((unsigned)((s.i32 >> 16) & 0xff), fp);
> putc((unsigned)((s.i32 >> & 0xff), fp);
> putc((unsigned)(s.i32 & 0xff), fp);
>
> putc((s.i16 >> & 0xff, fp);
> putc(s.i16 & 0xff, fp);
>
> Why the & 0xff ? The putc function casts its argument to an unsigned
> char, so anything but the 8 lower bits is automatically discarded. And
> the code already assumes the a char is 8 bits.

If the representation of negative integers isn't two's complement,
then converting to unsigned char
is different from discarding bits when s.i16 is negative.

--
pete

Jorge Peixoto
Guest
Posts: n/a

 10-26-2007
On Oct 26, 8:46 pm, pete <(E-Mail Removed)> wrote:
> Jorge Peixoto wrote:
>
> > In the answer to question 12.42 of the C FAQ, we have this code:

>
> > putc((unsigned)((s.i32 >> 24) & 0xff), fp);
> > putc((unsigned)((s.i32 >> 16) & 0xff), fp);
> > putc((unsigned)((s.i32 >> & 0xff), fp);
> > putc((unsigned)(s.i32 & 0xff), fp);

>
> > putc((s.i16 >> & 0xff, fp);
> > putc(s.i16 & 0xff, fp);

>
> > Why the & 0xff ? The putc function casts its argument to an unsigned
> > char, so anything but the 8 lower bits is automatically discarded. And
> > the code already assumes the a char is 8 bits.

>
> If the representation of negative integers isn't two's complement,
> then converting to unsigned char
> is different from discarding bits when s.i16 is negative.
>
> --
> pete

It doesn't matter.

The standard guarantees (according to http://c-faq.com/decl/inttypes.html)
that an unsigned char can hold any integer from 0 to 255. Since we are
already assuming that char is 8 bits, it can hold at most 256 numbers;
there are already 256 numbers between 0 and 255, so 0-255 is exactly
the range of numbers that an unsigned char can hold.

As far as I know (if I am wrong here please correct me), when you
convert from an integer to an unsigned, shorter one, the result is the
nonnegative remander in the division by a number that is 1 bigger
than the maximum number that can be represented by the smaller type.
In our case, this number is 256.

Taking the remainder modulo 256 is equivalent to bitwise and with
0xff, isn't it?

pete
Guest
Posts: n/a

 10-26-2007
Jorge Peixoto wrote:
>
> On Oct 26, 8:46 pm, pete <(E-Mail Removed)> wrote:
> > Jorge Peixoto wrote:
> >
> > > In the answer to question 12.42 of the C FAQ, we have this code:

> >
> > > putc((unsigned)((s.i32 >> 24) & 0xff), fp);
> > > putc((unsigned)((s.i32 >> 16) & 0xff), fp);
> > > putc((unsigned)((s.i32 >> & 0xff), fp);
> > > putc((unsigned)(s.i32 & 0xff), fp);

> >
> > > putc((s.i16 >> & 0xff, fp);
> > > putc(s.i16 & 0xff, fp);

> >
> > > Why the & 0xff ? The putc function casts its argument to an unsigned
> > > char, so anything but the 8 lower bits is automatically discarded. And
> > > the code already assumes the a char is 8 bits.

> >
> > If the representation of negative integers isn't two's complement,
> > then converting to unsigned char
> > is different from discarding bits when s.i16 is negative.
> >
> > --
> > pete

>
> It doesn't matter.
>
> The standard guarantees (according to http://c-faq.com/decl/inttypes.html)
> that an unsigned char can hold any integer from 0 to 255. Since we are
> already assuming that char is 8 bits, it can hold at most 256 numbers;
> there are already 256 numbers between 0 and 255, so 0-255 is exactly
> the range of numbers that an unsigned char can hold.
>
> As far as I know (if I am wrong here please correct me), when you
> convert from an integer to an unsigned, shorter one, the result is the
> nonnegative remander in the division by a number that is 1 bigger
> than the maximum number that can be represented by the smaller type.
> In our case, this number is 256.
> Taking the remainder modulo 256 is equivalent to bitwise and with
> 0xff, isn't it?

No.

There are three allowable ways to represent (-1) in 16 bits:
1111 1111 1111 1111
1111 1111 1111 1110
1000 0000 0000 0001

If s.i16 has a value of (-1),
then (s.i16 & 0xff) can have a value of either
255, or 254, or 1.

((unsigned char)-1) is always equal to UCHAR_MAX.

--
pete

pete
Guest
Posts: n/a

 10-26-2007
CBFalconer wrote:
>
> Jorge Peixoto wrote:
> >
> > In the answer to question 12.42 of the C FAQ, we have this code:
> >
> > putc((unsigned)((s.i32 >> 24) & 0xff), fp);
> > putc((unsigned)((s.i32 >> 16) & 0xff), fp);
> > putc((unsigned)((s.i32 >> & 0xff), fp);
> > putc((unsigned)(s.i32 & 0xff), fp);
> >
> > putc((s.i16 >> & 0xff, fp);
> > putc(s.i16 & 0xff, fp);
> >
> > Why the & 0xff ?
> > The putc function casts its argument to an unsigned char,
> > so anything but the 8 lower bits is automatically discarded.
> > And the code already assumes the a char is 8 bits.

>
> Where did you get the magic number 8 there?

It says so, here: http://c-faq.com/stdio/extconform.html

--
pete

CBFalconer
Guest
Posts: n/a

 10-27-2007
Jorge Peixoto wrote:
> pete <(E-Mail Removed)> wrote:
>> Jorge Peixoto wrote:
>>
>>> In the answer to question 12.42 of the C FAQ, we have this code:

>>
>>> putc((unsigned)((s.i32 >> 24) & 0xff), fp);
>>> putc((unsigned)((s.i32 >> 16) & 0xff), fp);
>>> putc((unsigned)((s.i32 >> & 0xff), fp);
>>> putc((unsigned)(s.i32 & 0xff), fp);
>>> putc((s.i16 >> & 0xff, fp);
>>> putc(s.i16 & 0xff, fp);

>>
>>> Why the & 0xff ? The putc function casts its argument to an
>>> unsigned char, so anything but the 8 lower bits is automatically
>>> discarded. And the code already assumes the a char is 8 bits.

>>
>> If the representation of negative integers isn't two's complement,
>> then converting to unsigned char is different from discarding bits
>> when s.i16 is negative.

>
> It doesn't matter.
>
> The standard guarantees (according to http://c-faq.com/decl/inttypes.html)
> that an unsigned char can hold any integer from 0 to 255. Since we
> are already assuming that char is 8 bits, it can hold at most 256
> numbers; there are already 256 numbers between 0 and 255, so 0-255
> is exactly the range of numbers that an unsigned char can hold.

IMO the fact that the FAQ makes (and documents) assumptions about
CHAR_BIT is no excuse for doing the same in this newsgroup,
especially without clearly so documenting. In other words, it does
matter, and omitting it will lead all sorts of innocent newbies
into dingy dark despondent passages. Look with especial suspicion
on any constant '8' in your code.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

--
Posted via a free Usenet account from http://www.teranews.com

Jorge Peixoto
Guest
Posts: n/a

 10-27-2007
> If s.i16 has a value of (-1),
> then (s.i16 & 0xff) can have a value of either
> 255, or 254, or 1.
>
> ((unsigned char)-1) is always equal to UCHAR_MAX.
>
> --
> pete

I didn't know that. So the bitwise operators are machine-dependent?
Are you telling me that the following simple code

#include <stdio.h>

int main (void) {
unsigned t = 256;
t &= 0xff;
printf ("%u\n", t);
return 0;
}

is machine dependent*? I thought that the bitwise operators would
behave as if the number is in two's complement, in any machine. It is
amazing if the simple code above is machine dependent.

* Even positive numbers may be represented in a crazy way. On the
Deathstation, positive numbers are represented in base 1, that is, the
number is the number of 1s in the variable. So 0 is all bits 0, 1 is
1, two is 11, three is 111, etc.

James Kuyper
Guest
Posts: n/a

 10-27-2007
Jorge Peixoto wrote:
....
> I didn't know that. So the bitwise operators are machine-dependent?

There are three permitted representations for negative values of signed
integer types; which one is actually used is implementation-defined.

The binary | and & operators are defined by the standard only in terms
of their operations on value and sign bits; the consequences of that
definition when applied to signed types are therefore tied to which of
those three representations is used for negative values.

> Are you telling me that the following simple code
>
> #include <stdio.h>
>
> int main (void) {
> unsigned t = 256;
> t &= 0xff;
> printf ("%u\n", t);
> return 0;
> }
>
> is machine dependent*?

No. You'd have to use a signed type with a negative value in order to
get behavior that is implementation-defined.