Question

Let consider the following program test.c:

#include <stdio.h>

struct test {
    unsigned int a:5;
};

int main () {
    unsigned int i;
    struct test t = {1};
    for (i = 0; i < t.a << 1; i++)
        printf("%u\n", i);
    return 0;
}

When compiled with gcc -Wsign-compare test.c the following warning is produced (tested with gcc 4.8.1):

test.c:9:19: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
     for (i = 0; i < t.a << 1; i++)
                   ^

clang -Wsign-compare test.c produces the following (tested with clang 3.2):

test.c:9:19: warning: comparison of integers of different signs: 'unsigned int' and 'int' [-Wsign-compare]
    for (i = 0; i < t.a << 1; i++)
                ~ ^ ~~~~~~~~
1 warning generated.

Thus the right operand, a shifted unsigned bit field, becomes a signed int. This warning shows for any bit field value between 1 and 31 included. For higher values no warning is produced. This is weird.

This was tested with a bit field of type unsigned short, unsigned int and unsigned long. The latter do not show any warning for bit field values between 32 and 64 included.

When no shifting is done there is no warning, hence the bit field is unsigned as expected.

Why bit fields of size lower than 32 bits become signed when shifted? I assume this is not a bug since this is consistent with both gcc and clang. I must be missing some info about how bit fields (or shifting) work but what? How can shifting an unsigned value yield a signed value?

Was it helpful?

Solution

Integer promotions are applied to the operands of shift covered in the draft C99 standard section 6.5.7 Bitwise shift operators paragraph 3 which says (emphasis mine going forward):

The integer promotions are performed on each of the operands.[...]

and the integer promotion of a bit-field is covered in section 6.3.1.1 Boolean, characters, and integers paragraph 2 which says:

The following may be used in an expression wherever an int or unsigned int may be used:

and contains the following bullet:

A bit-field of type _Bool, int, signed int, or unsigned int.

and then says:

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions.

it was clarified in the draft C11 standard:

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.58) All other types are unchanged by the integer promotions.

So this is expected behavior.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top