[comp.lang.c] is this broken or what?

wsmith@mdbs.UUCP (Bill Smith) (01/23/90)

I should post this in the appropriate Gnu group, but we have be cut off from 
most of the news groups for the time being.

	unsigned u = 0;

	if (u-- < 4)
		printf("yes\n");
	else
		printf("no\n");

The Data General Aviion 5000 (an 88000 machine) version of GCC converts this 
into:

	unsigned u = 0;

	if(--u < 3) ....

for the assembly.

This obviously will produce counter-intuitive results.

Bill Smith
pur-ee!mdbs!wsmith

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (01/23/90)

In article <1482@mdbs.UUCP> wsmith@mdbs.UUCP (Bill Smith) writes:

If you didn't see the original post this may be heavily trimmed...

| [ original source ]
|
| 	unsigned u = 0;
| 
| 	if (u-- < 4)
| 		printf("yes\n");

| The Data General Aviion 5000 (an 88000 machine) version of GCC converts this 
| into:
| 
| 	unsigned u = 0;
| 
| 	if(--u < 3) ....

| This obviously will produce counter-intuitive results.

  This will generate faster code, due to not keeping the original value
of u around, but it looks as if there would be a surprise if the value
of u were all ones (~0). To wit:

	unsigned u;
	u = ~0;
	if (u-- < 4) /* this is false, value tested is large # */
	if (--u < 3) /* true, value tested is zero */

  This *looks like* an unsafen optimization unless the compiler is sure
that the value of u is never all ones.
-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
            "Stupidity, like virtue, is its own reward" -me

ping@cubmol.bio.columbia.edu (Shiping Zhang) (01/23/90)

In article <1482@mdbs.UUCP> wsmith@mdbs.UUCP (Bill Smith) writes:
>	unsigned u = 0;
>
>	if (u-- < 4)
>		printf("yes\n");
>	else
>		printf("no\n");
>
>The Data General Aviion 5000 (an 88000 machine) version of GCC converts this 
>into:
>
>	unsigned u = 0;
>
>	if(--u < 3) ....
>
>for the assembly.
>

To me, the codes in the two cases are same.



-ping

kohli@gemed (Mr. Bad Judgment) (01/24/90)

In article <1990Jan23.155910.2439@cubmol.bio.columbia.edu>,
ping@cubmol.bio.columbia.edu (Shiping Zhang) writes:
<In article <1482@mdbs.UUCP> wsmith@mdbs.UUCP (Bill Smith) writes:
<>	unsigned u = 0;
<>
<>	if (u-- < 4)
<>		printf("yes\n");
<>	else
<>		printf("no\n");
<>
<>The Data General Aviion 5000 (an 88000 machine) version of GCC converts this 
<>into:
<>
<>	unsigned u = 0;
<>
<>	if(--u < 3) ....
<>
<>for the assembly.
<>
<
<To me, the codes in the two cases are same.
<
note the "unsigned" declaration:

	unsigned u = 0;

	if (u-- < 4)...
		if( 0x0 < 4 ) 	/* and THEN u = 0xffffffff */

this is NOT the same as:

	if(--u < 3)...
		if( (unsigned)0xffffffff < 3 )

These statements do not have the same logical value.  What Bill is
suggesting is that DG's compiler didn't account for the possibility
of the "negative" zero crossing of an unsigned number resulting in a number
greater than zero, i.e., it doesn't consider the case where
	( a < b ) != ((a-1) < (b-1)),
such as in Bill's example.

Jim Kohli
GE Medical

tim@nucleus.amd.com (Tim Olson) (01/24/90)

In article <1990Jan23.155910.2439@cubmol.bio.columbia.edu> ping@cubmol.bio.columbia.edu (Shiping Zhang) writes:
| In article <1482@mdbs.UUCP> wsmith@mdbs.UUCP (Bill Smith) writes:
| >	unsigned u = 0;
| >
| >	if (u-- < 4)
| >		printf("yes\n");
| >	else
| >		printf("no\n");
| >
| >The Data General Aviion 5000 (an 88000 machine) version of GCC converts this 
| >into:
| >
| >	unsigned u = 0;
| >
| >	if(--u < 3) ....
| >
| >for the assembly.
| >
| 
| To me, the codes in the two cases are same.

Check out what happens when u == 0.  Yes, it is an unsafe optimization
which should not be performed.


	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)

desj@idacrd.UUCP (David desJardins) (01/24/90)

From article <1482@mdbs.UUCP>, by wsmith@mdbs.UUCP (Bill Smith):
> 	unsigned u = 0;
> 	if (u-- < 4)

> 	unsigned u = 0;
> 	if(--u < 3) ....

   Can someone closely familiar with the ANSI standard tell us what
are the allowable things which might happen when one decrements the
unsigned value 0?  Certainly there are many compilers which will
assign a large positive value to the result, and so presumably the
standard allows this.  Can an ANSI-compliant compiler:

(1) Assign some other new value (e.g., zero)?
(2) Generate a run-time error?

I would presume that both of these are legal responses, but I wouldn't
mind hearing that from someone with more direct knowledge.

   As for the example code, I don't have any sympathy at all, although
I do grudgingly admit that that particular optimization probably isn't
a good idea.

   -- David desJardins

knudsen@cbnewsd.ATT.COM (michael.j.knudsen) (02/01/90)

In article <1093@sdrc.UUCP>, scjones@sdrc.UUCP (Larry Jones) writes:
> i-- also overflows), but not if i is unsigned (since unsigned
> arithmetic never overflows).

Excuse me -- one of us needs either a more reliable drugs supplier,
or a newer dictionary.  Unsigned arithmetic certainly can overflow--
it just gives you twice the headroom before it happens.
Doing i-- where i==0 will give a big surprise.
So will adding two positive numbers big enuf to wrap around.
Is this behavior not labeled "overflow"?  Correct me if I'm
wrong about this.
-- 
Mike Knudsen  knudsen@ihlpl.att.com   (708)-713-5134
"Round and round the while() loop goes;
        Whether it stops," Turing says, "no one knows."

knudsen@cbnewsd.ATT.COM (michael.j.knudsen) (02/01/90)

One of my "favorite" bugs is
	unsigned	i;
	...
	while(i >= 0) {......}

You can wait a long time for this to terminate....

My question is whether (i >= 0) is ALWAYS TRUE for unsigned i
in all dialects of C (including ANSI) and all hardware architectures,
or am I missing something?

I ask this partly because apparently ANSI has defined "overflow"
to require "change in sign", thus they can say with a straight face
that "unsigned ints never overflow".  I'd like to see their faces
when they try telling that to the hardware (remember that?)
that generates interrupts on overflow.
Seriously, unsigned declarations just control how the compiler
chooses conditional branch instructions when compiling |>| etc.
("higher" versus "greater"), so it's too late to call off
hardware overflow interrupts after a subtraction.

Or does ANSI require that such interrupts be disabled before
executing unsigned comparisons, and re-enabled beofre the next signed
one?
-- 
Mike Knudsen  knudsen@ihlpl.att.com   (708)-713-5134
"Round and round the while() loop goes;
        Whether it stops," Turing says, "no one knows."

meissner@osf.org (Michael Meissner) (02/02/90)

In article <12981@cbnewsd.ATT.COM>, knudsen@cbnewsd.ATT.COM
(michael.j.knudsen) writes:

| One of my "favorite" bugs is
| 	unsigned	i;
| 	...
| 	while(i >= 0) {......}
| 
| You can wait a long time for this to terminate....
| 
| My question is whether (i >= 0) is ALWAYS TRUE for unsigned i
| in all dialects of C (including ANSI) and all hardware architectures,
| or am I missing something?
| 
| I ask this partly because apparently ANSI has defined "overflow"
| to require "change in sign", thus they can say with a straight face
| that "unsigned ints never overflow".  I'd like to see their faces
| when they try telling that to the hardware (remember that?)
| that generates interrupts on overflow.
| Seriously, unsigned declarations just control how the compiler
| chooses conditional branch instructions when compiling |>| etc.
| ("higher" versus "greater"), so it's too late to call off
| hardware overflow interrupts after a subtraction.
| 
| Or does ANSI require that such interrupts be disabled before
| executing unsigned comparisons, and re-enabled beofre the next signed
| one?

The ANSI standard requires that unsigned arithmetic be done modulus
2**n (where n is the wordsize of the unsigned int or long).  This
specifically means on machines that insist on interrupting on
overflow, that either the compiler generates code to turn off such
interrupts before each unsigned operation; or fix the exception
handler to recognize such cases, and do the right thing (by continuing
the program).

For example, the Data General MV/Eclipse machine had a bit in the PSW
saying whether or not integer overflow interrupts would be generated,
and the function prologue would set the bit appropriately.  There were
also instructions to turn on and off the interrupts for the function.
By default, the C compiler always turned off these interrupts, but it
had an option to enable interrupts.  If the option was used, before
each unsigned instruction, the compiler would then turn off
interrupts, do the instruction, and turn them back on.....
--
Michael Meissner	email: meissner@osf.org		phone: 617-621-8861
Open Software Foundation, 11 Cambridge Center, Cambridge, MA

Catproof is an oxymoron, Childproof is nearly so

henry@utzoo.uucp (Henry Spencer) (02/03/90)

In article <12981@cbnewsd.ATT.COM> knudsen@cbnewsd.ATT.COM (michael.j.knudsen) writes:
>My question is whether (i >= 0) is ALWAYS TRUE for unsigned i
>in all dialects of C (including ANSI) and all hardware architectures,
>or am I missing something?

There is undoubtedly someone, somewhere, with a C compiler sufficiently
broken that it's not true.  All sane compilers consider it true.

>I ask this partly because apparently ANSI has defined "overflow"
>to require "change in sign", thus they can say with a straight face
>that "unsigned ints never overflow".  I'd like to see their faces
>when they try telling that to the hardware (remember that?)
>that generates interrupts on overflow.

Standard C compilers must generate code that does not interrupt -- or
at least acts as if it did not interrupt -- when an unsigned number wraps
around.  This is a guaranteed property of the language, not something
that's left up to the implementation.

>Seriously, unsigned declarations just control how the compiler
>chooses conditional branch instructions when compiling |>| etc.
>("higher" versus "greater"), so it's too late to call off
>hardware overflow interrupts after a subtraction.

Please justify this statement.  It's not true in modern C.  In fact, it
was never true -- even K&R1 is explicit about unsigned arithmetic
being modular arithmetic (in which there is no such thing as overflow).
Don't confuse the bizarre properties of specific hardware with the
documented behavior of the language.

>Or does ANSI require that such interrupts be disabled before
>executing unsigned comparisons, and re-enabled beofre the next signed
>one?

ANSI requires that unsigned numbers implement modular arithmetic.  This
requires that nothing untoward happen when unsigned arithmetic wraps
around.  If disabling interrupts is what it takes, then that's what has 
to be done.  On most machines, there are easier ways.  Most current C
implementations ignore signed overflow and hence would always run with
that interrupt disabled anyway.  An implementation which catches signed
overflow must arrange not to catch unsigned wraparound.
-- 
1972: Saturn V #15 flight-ready|     Henry Spencer at U of Toronto Zoology
1990: birds nesting in engines | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

mark.levy@canremote.uucp (MARK LEVY) (02/04/90)

dP>Are we to infer from this discussion that the ANSI standard requires
dP>comparisons like the one we are talking about to work properly?  That
dP>is, what is the prescribed behavior of

dP>        int i=MAXINT, j=(-MAXINT);
dP>        if (i > j) printf ("foo");

dP>Since i-j is negative, not positive, I would expect most compilers
dP>*not* to print "foo".
   
   I am not up on the ANSI standards that have been proposed, but as
I recall, the K&R standard was 0 == FALSE and anything else == TRUE.

dP>I don't even know what happens when you compare an unsigned value to a
dP>signed value.  That is, in the test

dP>        unsigned int i;
dP>        if (i >= 0) ...

   The use of 2's complement will avoid any kind of problem of 
positive or negative zero.  A compiler might flag an incompatible
data type comparison here.  My guess is that if the high order bit
in i is set, the expression will evaluate false, provided that it
compiled.

dP>is i converted to a signed type before the comparison is performed?
dP>This could certainly make a mess if i is all ones.

   Don't ever assume anything about type conversions.  If you're not
sure, use pleanty of casts and parens.

Mark
---
 ~ DeLuxe 1.11a18 #3019
 ~ QNet 2.04a:NorthAmeriNet: Sound Advice BBS ~ Gladstone ~ MO

chris@mimsy.umd.edu (Chris Torek) (02/05/90)

>>... what is the prescribed behavior of
>>        int i=MAXINT, j=(-MAXINT);
>>        if (i > j) printf ("foo");

The ANSI conformant C program

	#include <stdio.h>
	#include <limits.h>

	int main(void) {
		int i = INT_MAX, j = INT_MIN;
		if (i > j) printf("foo\n");
		return 0;
	}

must print `foo' (at least on a hosted implementation).

In article <90020407120313@masnet.uucp> mark.levy@canremote.uucp (MARK LEVY)
writes:
>   I am not up on the ANSI standards that have been proposed, but as
>I recall, the K&R standard was 0 == FALSE and anything else == TRUE.

This is correct, but has nothing to do with the answer to the previous
question.

>>        unsigned int i;
>>        if (i >= 0) ...

>   The use of 2's complement will avoid any kind of problem of 
>positive or negative zero.  A compiler might flag an incompatible
>data type comparison here.  My guess is that if the high order bit
>in i is set, the expression will evaluate false, provided that it
>compiled.

Henry Spencer has already given a correct answer; there is no need for
a false one.  If the variable `i' has ever been set after being created,
the test will always succeed (so that the code given as `...' will be
executed), and indeed, a compiler is free not to generate any code at
all for the test, and to produce a warning.

>   Don't ever assume anything about type conversions.  If you're not
>sure, use pleanty of casts and parens.

If you have a compiler that claims to conform to the ANSI standard, you
can make any assumption that the ANSI standard says must hold.  If you
are working with older compilers, be wary; but in this case you need not
worry: all unsigned numbers are greater than or equal to zero.  The only
way for the code to fail is if i has never been assigned a value: in
such a case it might, e.g., have an `invalid value' type tag that causes
a run-time exception when tested.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris