On Tue, 08 Mar 2011 12:16:29 EST erik quanstrom <quans...@quanstro.net> wrote: > for this > > uvlong u, i; > > i = 31; > u = 0xff00000000000000ull; > > i get > > u & 1<<i -> 0xff00000000000000ull > u & 0x80000000 -> 0 > u & (int)0x80000000 -> 0xff00000000000000ull > u & -2147483648 -> 0 > > to put a finer point on it, > > (uvlong)(1<<i) -> 0xffffffff80000000 > (uvlong)(0x80000000) -> 0x80000000 > (uvlong)(int)0x80000000 -> 0xffffffff80000000 > (uvlong)-2147483648 -> 0x80000000 > > so it seems clear that constants are treated as if unsigned, regardless, > but variables are not? > > can this be correct? i hate to hazzard guesses about the c standard.
1 is signed. 1u is unsigned (see 6.4.4.1). 0x80000000 doesn't fit in an int so it is an unsigned int. 0x100000000 won't fit in an unsigned int so it will pick the next type in the table that is big enough, which is long long int. Nice, eh?! For shift operators, type of the result is that of the "promoted left operand" (see 6.5.7). So 1<<i is an int. It is first promoted to a long long int and then to unsigned long long int. As for conversions, a smaller sized (lower ranked) value is first converted to a larger sized (higher ranked) value of the *same* type before any signedness conversion but can't find where it says so in the std. May be 6.3.1.1. The value of (int)0x80000000 is an unsigned int to int conversion and since its value doesn't fit in an int, the result is implementation defined. Usually it just becomes -2147483648 (since that is more efficient than anything else). Both clang and gcc fail the following (but I can well believe plan9 C compiler behaves differently). > u & -2147483648 -> 0 > (uvlong)-2147483648 -> 0x80000000 -2147483648 is first converted to long long int (preserving its value) and then to unsigned long long int. So this is 0xffffffff80000000ull. --- #define check(x) do if (!(x)) printf("%s:%d: check failed: %s\n", __FILE__, __LINE__, #x); while(0) typedef unsigned long long uvlong; int main() { uvlong i = 31; uvlong u = 0xff00000000000000ull; check((u & 1<<i) == 0xff00000000000000ull); check((u & 0x80000000) == 0); check((u & (int)0x80000000) == 0xff00000000000000ull); check((u & -2147483648) == 0); check((uvlong)(1<<i) == 0xffffffff80000000ull); check((uvlong)(0x80000000) == 0x80000000ull); check((uvlong)(int)0x80000000 == 0xffffffff80000000ull); check((uvlong)-2147483648 == 0x80000000ull); check((uvlong)-2147483648 == 0xffffffff80000000ull); return 0; }