Wouter Vermaelen <wouter.vermaelen@xxxxxxxxxx> writes: > This is unexpected to me, because the field 'a' is already unsigned, so > adding an extra cast to unsigned shouldn't change anything. In s.a < -1, the < operator performs (C99 6.5.8p3) the usual arithmetic conversions, which include (6.3.1.8p1) the integer promotions (6.3.1.1p2). In unsigned a : 27, the width of the bit-field is part of the type (6.7.2.1p9). If the int type is 32-bit as usual, then all possible values of s.a fit in int, and the result of the integer promotions is an int, even though the bit-field was declared as unsigned. I don't know if C89 had different rules for this. An extended C++ variant of your test program: #include <stdio.h> #include <typeinfo> namespace { const char *overload(int) { return "int"; } const char *overload(unsigned) { return "unsigned"; } } int main() { struct { unsigned a : 27; } s = {1}; printf("typeid(unsigned) = %s\n", typeid(unsigned).name()); printf("typeid(int) = %s\n", typeid(int).name()); printf("typeid(s.a) = %s\n", typeid(s.a).name()); printf("typeid(+s.a) = %s\n", typeid(+s.a).name()); printf("overload(s.a) = %s\n", overload(s.a)); printf("overload(+s.a) = %s\n", overload(+s.a)); printf("(s.a < -1) = %d\n", s.a < -1); printf("(((unsigned)s.a) < -1) = %d\n", ((unsigned)s.a) < -1); } compiled with GCC 4.4.5 on amd64 outputs: typeid(unsigned) = j typeid(int) = i typeid(s.a) = j typeid(+s.a) = i overload(s.a) = unsigned overload(+s.a) = int (s.a < -1) = 0 (((unsigned)s.a) < -1) = 1 > Is there any way to change the behavior of gcc (so make it output "1 1")? I don't think there is. In GCC trunk r108723 (which I happened to have at hand), it looks like the integer promotions are implemented in gcc/c-typeck.c (perform_integral_promotions) and gcc/c-common.c (c_promoting_integer_type_p). The TYPE_PRECISION comparisons in these functions do not check any options.