Skip to content

Those bit fields should have been unsigned….

September 16, 2004

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.


From → General

  1. 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.

  2. The footnote on C99 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
    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.

  3. by default gcc treats them as signed, as you noted. You can control it from the cmdline:
    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.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: