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;
}

Reply via email to