449,042 Members | 1,036 Online
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,042 IT Pros & Developers. It's quick & easy.

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

 P: n/a 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 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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. Oct 26 '07 #1
23 Replies

 P: n/a 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 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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. -- Posted via a free Usenet account from http://www.teranews.com Oct 26 '07 #2

 P: n/a On Oct 26, 5:58 pm, CBFalconer 24) & 0xff), fp); putc((unsigned)((s.i32 >16) & 0xff), fp); putc((unsigned)((s.i32 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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. Oct 26 '07 #3

 P: n/a 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 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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 Oct 26 '07 #4

 P: n/a On Oct 26, 8:46 pm, pete 24) & 0xff), fp); putc((unsigned)((s.i32 >16) & 0xff), fp); putc((unsigned)((s.i32 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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? Oct 26 '07 #5

 P: n/a Jorge Peixoto wrote: > On Oct 26, 8:46 pm, pete 24) & 0xff), fp); putc((unsigned)((s.i32 >16) & 0xff), fp); putc((unsigned)((s.i32 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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 Oct 26 '07 #6

 P: n/a 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 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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 Oct 26 '07 #7

 P: n/a 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 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. Oct 27 '07 #8

 P: n/a On Fri, 26 Oct 2007 14:17:56 -0700, Jorge Peixoto On Oct 26, 5:58 pm, CBFalconer 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 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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 beany 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 charis 8 bits. Read the answer to the question 12.42 of the FAQ. Indeed. And the FAQ explicitly says so ("This code assumes that getc reads 8-bit characters"). -- jay http://c-faq.com/ http://msdn2.microsoft.com/en-us/express/default.aspx http://www.gimpel.com/ http://www.ubuntu.com/ http://www.embedded.com/ Oct 27 '07 #9

 P: n/a Jorge Peixoto wrote: > .... snip ... > * 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. Not so. The fundamental binary representation of positive integers is specified in the standard. -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. -- Posted via a free Usenet account from http://www.teranews.com Oct 27 '07 #10

 P: n/a Jorge 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 >8) & 0xff), fp); ) putc((unsigned)(s.i32 & 0xff), fp); ) ) ) putc((s.i16 >8) & 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. Think about what would happen with this bit of code on a system where a char is 9 bits. What would the result be ? What exactly would putc be outputting ? SaSW, Willem -- Disclaimer: I am in no way responsible for any of the statements made in the above text. For all I know I might be drugged or something.. No I'm not paranoid. You all think I'm paranoid, don't you ! #EOT Oct 27 '07 #11

 P: n/a Willem wrote: Jorge 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 >8) & 0xff), fp); ) putc((unsigned)(s.i32 & 0xff), fp); ) ) ) putc((s.i16 >8) & 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. Think about what would happen with this bit of code on a system where a char is 9 bits. What would the result be ? What exactly would putc be outputting ? That char should be assumed to be 8 bits is part of the design specifications for this code, so that can't be the justification for the &0xff. Oct 27 '07 #12

 P: n/a * 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. Not so. The fundamental binary representation of positive integers is specified in the standard. So a machine that uses BCD would have to do emulation to be the target of a C implementation? In any event, I think this issue should be in the answer to the question. People will be thinking why is that &0xff needed, and the FAQ should be didactic. Oct 27 '07 #13

 P: n/a Jorge Peixoto wrote: .... So a machine that uses BCD would have to do emulation to be the target of a C implementation? Yes. Bitwise operators must be implemented as if operating on a binary representation of the value, which would presumably not be a simple operation on such a machine. Trinary machines (which have some interesting advantages in certain contexts compared to binary machines) would also be problematic. Oct 27 '07 #14

 P: n/a On Oct 26, 4:44 pm, pete 24) & 0xff), fp); putc((unsigned)((s.i32 >16) & 0xff), fp); putc((unsigned)((s.i32 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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 tohttp://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 Would 0xff on a 16 bit machine be represented as 0000 0000 1111 1111 In other words, would there be leading zero's before 1111 1111 ? Oct 27 '07 #15

 P: n/a Yes. Bitwise operators must be implemented as if operating on a binary representation of the value, which would presumably not be a simple operation on such a machine. Trinary machines (which have some interesting advantages in certain contexts compared to binary machines) would also be problematic. So the code here *is* redundant! This call putc((unsigned)((s.i32 >24) & 0xff), fp); is equivalent to this putc((unsigned)(s.i32 >24), fp); In the second call, you cast to unsigned char, which means taking the remainder modulo 256. In the first call, you perform bitwise and with 0xff; you are telling me that this will behave (for unsigned numbers, and this one is unsigned) as if the number was represented in two's complement; so this is equivalent to taking the remainder modulo 256. And I think that even the cast to unsigned is unneeded. Can you get different results from casting an integer to unsigned, then to unsigned char, instead of directly casting from integer to unsigned char? Oct 27 '07 #16

 P: n/a On Oct 27, 4:03 pm, Jorge Peixoto wrote: Yes. Bitwise operators must be implemented as if operating on a binary representation of the value, which would presumably not be a simple operation on such a machine. Trinary machines (which have some interesting advantages in certain contexts compared to binary machines) would also be problematic. So the code here *is* redundant! This call putc((unsigned)((s.i32 >24) & 0xff), fp); is equivalent to this putc((unsigned)(s.i32 >24), fp); In the second call, you cast to unsigned char, which means taking the remainder modulo 256. In the first call, you perform bitwise and with 0xff; you are telling me that this will behave (for unsigned numbers, and this one is unsigned) as if the number was represented in two's complement; so this is equivalent to taking the remainder modulo 256. Oh wait, he casts to unsigned *after* the and. In any event, that FAQ answer needs clarification ! Oct 27 '07 #17

 P: n/a "James Kuyper" So a machine that uses BCD would have to do emulation to be the targetof a C implementation? Yes. Bitwise operators must be implemented as if operating on a binary representation of the value, which would presumably not be a simple operation on such a machine. Trinary machines (which have some interesting advantages in certain contexts compared to binary machines) would also be problematic. BCD representations would be problematic for integer types, but not for floating point where they actually have interesting properties, especially for financial and accounting applications. -- Chqrlie. Oct 27 '07 #18

 P: n/a "James Kuyper" Jorge 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 >8) & 0xff), fp);) putc((unsigned)(s.i32 & 0xff), fp);))) putc((s.i16 >8) & 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.Think about what would happen with this bit of code on a system wherea char is 9 bits. What would the result be ? What exactly would putcbe outputting ? That char should be assumed to be 8 bits is part of the design specifications for this code, so that can't be the justification for the &0xff. That's the beauty of this code, it does not even assume char to be eight bit wide. It is not fully portable to weird obsolete non 2's complement architectures, but it does produce 4 octets on the stream even if CHAR_BIT != 8. If CHAR_BIT == 8, the mask is not necessary. -- Chqrlie. Oct 27 '07 #19

 P: n/a Chad wrote: > On Oct 26, 4:44 pm, pete

 P: n/a Jorge Peixoto wrote: > >Yes. Bitwise operators must be implemented as if operating on abinary representation of the value, which would presumably not bea simple operation on such a machine. Trinary machines (whichhave some interesting advantages in certain contexts compared tobinary machines) would also be problematic. So the code here *is* redundant! This call putc((unsigned)((s.i32 >24) & 0xff), fp); is equivalent to this putc((unsigned)(s.i32 >24), fp); No it isn't. What if a byte (or char) is larger than 8 bits? -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. -- Posted via a free Usenet account from http://www.teranews.com Oct 28 '07 #21

 P: n/a On Fri, 26 Oct 2007 12:30:16 -0700, 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 >8) & 0xff), fp); putc((unsigned)(s.i32 & 0xff), fp); putc((s.i16 >8) & 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. Well, suppose you have a 9-bit machine and you want to write a file in a 8-bit format. The most reasonable thing to do is not to use the most significant bit in each byte, i.e. only using bytes from 0000 to 0377. Now, suppose that you must read from such a file. You could simply assume that the most significant bit is never set, but could also discard it anyway, simply ignoring it. This way the code wouldn't break if, er..., alpha particles set the most significant bit of a byte. -- Army1987 (Replace "NOSPAM" with "email") A hamburger is better than nothing. Nothing is better than eternal happiness. Therefore, a hamburger is better than eternal happiness. Oct 28 '07 #22

 P: n/a On Sat, 27 Oct 2007 20:41:59 +0200, Charlie Gordon wrote: "James Kuyper" Jorge Peixoto wrote: >>So a machine that uses BCD would have to do emulation to be the targetof a C implementation? Yes. [...] BCD representations would be problematic for integer types, but not for floating point where they actually have interesting properties, especially for financial and accounting applications. Indeed, the standard doesn't require FLT_RADIX to be a power of 2. -- Army1987 (Replace "NOSPAM" with "email") A hamburger is better than nothing. Nothing is better than eternal happiness. Therefore, a hamburger is better than eternal happiness. Oct 28 '07 #23

 P: n/a On Oct 28, 1:10 pm, CBFalconer 24) & 0xff), fp); is equivalent to this putc((unsigned)(s.i32 >24), fp); No it isn't. What if a byte (or char) is larger than 8 bits? The OP stipulated that this code is written with the assumption of char being 8 bits. Oct 28 '07 #24

### This discussion thread is closed

Replies have been disabled for this discussion.