[comp.lang.c] semantics of arith comparisons

steve@taumet.com (Stephen Clamage) (02/07/91)

matsc@sics.se (Mats Carlsson) writes:

>In the following program, the functions test1 and test2 are meant to
>be equivalent.  The only difference is that a variable is introduced in
>test2 to temporarily hold a value. ... [example shrunk to save space]

>test1(int i) {
>  if (i + 0x40000000 >= 0) return 1;
>  else return 0;
>}

>test2(int i) {
>  int j = i + 0x40000000;
>  if (j >= 0) return 1;
>  else return 0;
>}

The temp you introduced is NOT the same type as the expression, and that
is the reason for the difference.

Hex constants are of type unsigned int, and so in test1 the value of
(i+0x40000000) is type unsigned int.  (When you add an int and an unsigned
int, the result is type unsigned int.) In the comparison to 0, the
top bit is a magnitude bit, not a sign bit.

In test2, you store the result of (i+0x40000000) in an int.  This
preserves the bit pattern, but the top bit is now treated as a sign bit
in the comparison.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

gwyn@smoke.brl.mil (Doug Gwyn) (02/07/91)

In article <1991Feb6.085315.10468@sics.se> matsc@sics.se (Mats Carlsson) writes:
>This must be a compiler bug.  Surely the value of an expression shouldn't
>change by storing it in a variable *of the same type* as the expression
>has.

All bets are off when overflow occurs.  You were lucky you didn't get
an ABEND instead of merely strange numerical results.  For integer
arithmetic with reasonable overflow semantics, use an unsigned type.

gwyn@smoke.brl.mil (Doug Gwyn) (02/07/91)

In article <589@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>Hex constants are of type unsigned int, ...

No, 0x40000000 in this example should have had type int.

steve@taumet.com (Stephen Clamage) (02/08/91)

I wrote:

>Hex constants are of type unsigned int ...

This is not correct, as Andy Koenig and Doug Gwyn pointed out.

In ANSI C (3.1.3.2), the type of a hex constant (without L or U suffix)
is the first in this list in which its value can be represented:
int, unsigned int, long int, unsigned long int.

In pre-ANSI C, a the type of a hex constant (without an L suffix) was int
if it would fit in an unsigned int, and long otherwise.  This led to some
bizarre consequences:  on a system with 16-bit ints, 0xFFFF had type int
and the value -1, while 65535 had type long and value 65535.

The ANSI rules give the more natural result that 0xFFFF has the value
65535 whether ints are 16 bits or longer.  If ints are 16 bits, the type
of 0xFFFF is unsigned int; if bits are longer, the type is int.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com