Bug constant folding unsigned chars
Kirk Hays
hays at isc.intel.com
Sat Jul 28 06:15:17 AEST 1990
In article <9007250601.AA07615 at csvax.cs.caltech.edu> daveg at CSVAX.CS.CALTECH.EDU (David Gillespie) writes:
>I tried the following program on gcc 1.37.1 under HP-UX 7.0. I was
>checking that IsUnsigned would be folded to a constant at compile-time.
>It was, but in two cases the result was wrong!
Sorry, but the macro is K&R correct(sometimes), ANSI wrong, as the value
conversion rules were open in K&R, but defined in ANSI.
What you are seeing is ANSI compiler behavior.
>
> #define IsUnsigned(x) (((x)*0-2)/2+1)
>
> int a;
> unsigned int b;
> short c;
> unsigned short d;
> char e;
> unsigned char f;
>
> main() {
> printf("%d, %d, %d, %d, %d, %d\n",
> IsUnsigned(a), IsUnsigned(b),
> IsUnsigned(c), IsUnsigned(d),
> IsUnsigned(e), IsUnsigned(f));
> }
>
>The output using cc is
>
> 0, -2147483648, 0, -2147483648, 0, -2147483648
One of the correct non-ANSI answers.
There are several.
>
>but the output using gcc is
>
> 0, -2147483648, 0, 0, 0, 0
The only correct ANSI answer (on 32 bit machines). See below for explanation.
>
>(This IsUnsigned macro is due to Karl Heuer on comp.lang.c.)
>
> -- Dave
What you're seeing here is the difference between ANSI and pre-ANSI
compilers.
In ANSI, before the arithmetic operators are applied to the values, they
are promoted to *int*, unless their possible values prevent them from
being represented as *int*, in which case, they are converted to *unsigned
int* (for all types less than or equal to in size to an *int*).
In your program, all of the signed and unsigned types, except _unsigned int_,
have values representable as *int*, so they are converted to *int* prior to
the operations being performed, and the constants follow suit.
That is why ONLY the *unsigned int* case works.
Longs and unsigned longs are subject to a different (but equivalent)
conversion rule.
See section 3.2 of the ANSI standard (ANS 3.159-1989) for more detail.
Here is an extension of the above program which demonstrates my assertions.
The only correct answers with an ANSI compiler on a 32 bit machine are:
0, -2147483648, 0, 0, 0, 0, 0, -2147483648
0, -2147483648, 0, 0, 0, 0, 0, -2147483648
For any compiler on any architecture, if the two lines are different from
each other, COMPLAIN LOUDLY to your vendor until they fix it!
---------------cut here------------------
#define IsUnsigned(x) (((x)*0-2)/2+1)
signed int a;
unsigned int b;
signed short c;
unsigned short d;
signed char e;
unsigned char f;
long g;
unsigned long h;
main() {
printf("%d, %d, %d, %d, %d, %d, %d, %d\n",
IsUnsigned(a), IsUnsigned(b),
IsUnsigned(c), IsUnsigned(d),
IsUnsigned(e), IsUnsigned(f),
IsUnsigned(g), IsUnsigned(h));
{
int zero= 0;
int one = 1;
int two = 2;
#define F(type) (((type)zero-(type)two)/(type)two+(type)one)
printf ("%d, %d, %d, %d, %d, %d, %d, %d\n",
F(int), F(unsigned int),
F(short), F(unsigned short),
F(char), F(unsigned char),
F(long), F(unsigned long));
}
}
---------------cut here------------------
Frankly, I am surprised that Karl Heuer blew the macro; he is the walking
lint, after all!
Most of this was hashed about in ~1986, I think, when the debate about
"value-preserving" vs. "sign-preserving" raged across the net.
--
Kirk Hays - I'm the NRA, NRA-ILA, CCRKBA, SAF, and Neal Knox is my lobbyist.
More information about the Comp.lang.c
mailing list