In article <>
Christian Kandeler <> wrote:
[code snipped]
>On a platform with 64-bit longs and 32-bit ints, this prints
>18446744071562067968, i.e. a number that has the upper 33 bits set to 1.
>This stunned me at first, but I think I have now figured out what happens:
>
>(1) Because the bit-field is only one bit wide, all its values fit into a
>signed int, so test.x is converted to one.
>(2) Therefore, the result of the shift operation is a signed int too.
>(3) Since the resulting value is negative on this platform, ULONG_MAX + 1 is
>added to it, yielding the value mentioned above.
>
>Is this correct?
Yes.
ANSI/ISO C has the "wrong" rules (according to me anyway

) for
handling mixes of signed and unsigned. The "right" rule is very
simple: "if any operand is unsigned, the result is unsigned."
This rule is simple and easy to understand, but sometimes gives
"surprising" results.
The ISO rule is: "If any operand is unsigned, it is widened, but
the resulting type depends on the possible ranges of values of the
original unsigned type and the wider type." This rule is complicated
and hard to understand, and *still* sometimes gives surprising
results. (Moreover, the results depend on the relative values of
the various *_MAXes, for non-bitfield types. In particular,
implementations with a USHRT_MAX of 65535 and an INT_MAX of 32767
behave differently from those with a USHRT_MAX of 65535 and an
INT_MAX of 2147483647, when doing arithmetic with "unsigned short".)
Because we are stuck with the horrible, near-impossible-to-reason-about,
implementation-dependent "value preserving" rules (am I laying it
on a little thick?

), your only recourses are intermediate
temporary variables or casts.
>... This could then easily be avoided by casting the bit-field to
>an unsigned int before the shift. However, the resulting program
>
>#include <stdio.h>
>
>int main(void)
>{
> struct test {
> unsigned int x : 1;
> } test;
>
> test.x = 1;
>
> printf("%lu\n", (unsigned long) ((unsigned int) test.x << 31));
> return 0;
>}
>
>still prints the same value with gcc 3.3.3. All other compilers I have tried
>(including gcc 4), print 2147483648, as I had originally expected. Is my
>assumption correct that gcc 3 is wrong here?
Gcc 3.3.3 is wrong here.
(Note that shifting an "unsigned int" 31 bits is itself at least
a little risky, since there are 16-bit "int" implementations.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.