Those bit fields should have been unsigned....

While porting some code to AMD 64 I came across strange behavior difference between gcc and the Sun C compiler. Compiling this small test program:
#include <stdio.h>

struct foo {
        int thirtyone:31;
        int bit:1;
};

struct foo one = {0 , 1};
struct foo zero = {0 , 0};

int
return_bit(struct foo \*p)
{
        return (p->bit);
}

int
main(int argc, char \*\*argv)
{
        printf("one %x\\n", return_bit(&one));
        printf("zero %x\\n", return_bit(&zero));
}
Running the above when compiled with the Sun compiler gave:
$; ./bitfield
one 1
zero 0
and gcc gave:
$; ./bitfield-gcc
one ffffffff
zero 0
Clearly gcc has sign extended the value which broke the real code I had. Making the bit field unsigned is obviously the right thing to do (as it is unsigned) but it has left me wondering which compiler is right or whether both are and this is a grey area.
Comments:

it's a grey area: you can't portably store '1' in a 1-bit signed bitfield. You'd need an unsigned bitfield if it were just one bit.

Posted by Calum Mackay on September 16, 2004 at 03:33 PM BST #

The footnote on C99 6.7.2.1p9 says:

104) As specified in 6.7.2 above, 
if the actual type specifier used is int 
or a typedef-name defined as int, 
then it is implementation-defined 
whether the bit-field is signed or unsigned.
So this is implementation-defined, which means an implementation has to document how it behaves. And Sun's compiler says in C user's guide:

C.1.9 J.3.9 Structures, Unions, Enumerations, and Bit-fields

    \* Whether a "plain" int bit-field is 
      treated as signed int bit-field 
      or as an unsigned int bit-field 
      (6.7.2, 6.7.2.1).

It is treated as an unsigned int. 
Unfortunately, gcc's info page doesn't say anything about this (other than the standard says it is implementation defined) - it's possible that my copy of gcc is slightly outdated (3.4.2) or it is documented somewhere else. So I don't know whether gcc documents this behavior somewhere but clearly it treats int as signed int.

Posted by Seongbae Park on September 16, 2004 at 03:33 PM BST #

by default gcc treats them as signed, as you noted. You can control it from the cmdline: `-fsigned-bitfields' `-funsigned-bitfields' `-fno-signed-bitfields' `-fno-unsigned-bitfields' These options control whether a bit-field is signed or unsigned, when the declaration does not use either `signed' or `unsigned'. By default, such a bit-field is signed, because this is consistent: the basic integer types such as `int' are signed types.

Posted by Calum Mackay on September 16, 2004 at 03:44 PM BST #

Post a Comment:
Comments are closed for this entry.
About

This is the old blog of Chris Gerhard. It has mostly moved to http://chrisgerhard.wordpress.com

Search

Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today