assigning an integer to the negation of ...
Chris Torek
chris at mimsy.UUCP
Wed Dec 21 02:47:55 AEST 1988
In article <1911 at pembina.UUCP> lake at alberta.UUCP (Robert Lake) writes:
> i = -(unsigned short)j;
[where i is an int and j is 1---j's type is irrelevant]
To figure out what one `should' get, follow the rules:
op value type
-- ----- ----
1a. j 1 lvalue, int
1b. expansion 1 rvalue, int
2a. (u_short) 1 temporary, u_short [note 1]
2b. expansion 1 rvalue, int or u_int [note 2]
3. - -1|-(u_int)1 rvalue, int or u_int
4a. i= -1 temporary, int
4b. expansion -1 rvalue, int
Notes:
1: u_T is a shorthand for `unsigned T'
2: u_int under `sign-preserving' rules, either under
dpANS `value-preserving' rules, depending on whether
sizeof(int) > sizeof(short); on Suns it would be int
So the correct answer is -1, not 65535, under either set of rules.
>If I run this program on a VAX 11/780 using 4.3 BSD, I obtain -1 as the
>answer. However, if I run this on a SUN using SUN OS 3.5, I obtain 65535
>as the answer. Who is right?
4.3BSD got it right; SunOS got it wrong (in the name of optimisation :-) ).
So what is going on in the table above?
Every time C uses a value for some operation, the value should be an
`rvalue'. It might be an lvalue or a `temporary'---the result of an
assignment, including casts, is a `temporary'; I made up the notion
just now, to provide a placeholder for the expressions that are neither
lvalues nor properly-expanded rvalues. If it is not already a properly
expanded rvalue, it is expanded, either according to unsigned-preserving
rules (in the table below) or value-preserving rules (which cannot be
listed except for specific compiler systems, since they depend on the
number of bits in each type).
original expansion
(lvalue or temp)
-------- ---------
signed char int
u_char u_int
short int
u_short u_int
int int (already proper)
u_int u_int (already proper)
long long (already proper)
u_long u_long (already proper)
Each expansion does the `obvious' thing: if the expansion is from
signed, any new high-order bits in the expanded signed version come
about by sign extension; if from unsigned, new high-order bits are
zeroes. (This holds true in both expansion systems.)
So why does the Sun compiler produce 65535?
All the expansions above are expensive on some machines---including
680x0s, where it takes up to two instructions per expansion, and
possibly a temporary register. If the compiler can prove to itself
that the expansion has no effect, it can suppress it. For instance,
if the assignment were:
u_short j;
j = -(u_short)(1);
we would have the sequence (unsigned-preserving rules)
1 (1, int, rvalue)
(u_short) (1, u_short, temp)
expand (1, u_int, rvalue)
- (0xffffffff, u_int, rvalue)
j= (0xffff, u_short, temp)
which puts 65535 in j. The expansion had no effect on the answer:
wihtout it, we have
1 (1, int, rvalue)
(u_short) (1, u_short, temp => fake rvalue)
- (0xffff, u_short, fake rvalue)
j= (0xffff, u_short, temp)
The SunOS 3.5 compiler incorrectly deduces that the expansion had no
effect (it forgets to look at the LHS of the assignment), so it drops
it from the expression tree and gets the wrong answer.
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain: chris at mimsy.umd.edu Path: uunet!mimsy!chris
More information about the Comp.lang.c
mailing list