Re: gcc bug?

David Mosberger-Tang (davidm@AZStarNet.com)
Sat, 16 Dec 1995 21:37:59 -0700


Randy> Hopefully someone here will know a way to work around this (preferably
Randy> a compile flag =) gcc seems to be doing sign extensions in places
Randy> where it ought not in some conditions (this verified against dec cc,
Randy> which compiles this code fine).

Randy> The code trinket:

Randy> unsigned char c = 0xca;
Randy> unsigned long l;
Randy>
Randy> l = c<<24;
Randy> printf("%lX\n",l);

Randy> l will be 0xFFFFFFFFCA000000 with gcc. And 0xCA000000 with cc (what I
Randy> want). gcc for osf/1 does the same, btw.

Just because another compiler does something differently does not
necessarily mean gcc is at fault. I don't have a C ref. manual handy,
but the C++ manual states:

C++ follows ANSI C in defining integral promotions as
"value-preserving." That is, a char, a short, or an int
bit field, or their signed or unsigned varieties, will
be widened to int if int can represent all the values of
the original type or to unsigned int otherwise.

Now, int certainly can represent all the values of unsigned char, so
variable c gets promoted to int. I presume the same
"value-preserving" rule applies for int->long promotion. If so,
notice that ((int)0xca000000) is a negative number. In order to
preserve this negative value, gcc thus has to pick "long int" as the
promoted type.

You get the desired result simply be saying:

l = ((unsigned)c)<<24;

Actually, unsigned long would be safer as that would work even with
shift amounts greater than 24.

--david