T
tom_usenet
I'm surprised at the different results I can get from code with and
without optimisation where overflow is involved.
I suspect this was "done to death" about 20 years ago, but
I can't find anything in comp.lang.c matching this. Is this
the "if you overflow the compiler can do whatever it likes"
clause?
The original problem I was trying to solve is why a simple
embedded "printf("%ld")" was printing random garbage when
handed -2147483648.
Here are the results for the following simple program with different
optimisation levels, in all cases "-O1" gives sane results and "-O2"
gives remarkably creative results.
The problems are:
1 - With "-O2" the second test in the following is optimised out:
as it "can't be true". Unless (num == -2147483648) in which
case it IS true, and is what I'm trying to correct for in
the function I was trying to fix.
if (num < 0L) num = -num;
if (num < 0L) stillNeg = 1;
2 - "-2147483647 + 1 == -2147483647" ???
3 - "-2147483647 == --2147483647" ???
This is the "sane" one without optimisation.
$ gcc --version
gcc (GCC) 4.3.4 20090804 (release) 1
$ gcc -Wall -O1 -o ox2 ox2.c
$ ./ox2
Function calls
2147483646
2147483647
-2147483648 Still negative
2147483647
2147483646
For loop
num = 2147483646 vnum = 2147483646
num = 2147483647 vnum = 2147483647
num = -2147483648 neg vnum = -2147483648 neg
num = 2147483647 vnum = 2147483647
num = 2147483646 vnum = 2147483646
This is the insane one with optimisation.
$ gcc -Wall -O2 -o ox2 ox2.c
$ ./ox2
Function calls
2147483646
2147483647
-2147483648 *** Missed the second test ***
2147483647
2147483646
For loop
num = 2147483646 vnum = 2147483646
num = 2147483647 vnum = 2147483647
num = 2147483647 vnum = -2147483648
num = 2147483647 vnum = -2147483647
num = 2147483647 vnum = -2147483646
^^ That got stuck ^^ ^^ That is negating when it shouldn't **
Here's the test code. Apologies for the "crammed style", I don't
usually write code that looks this bad:
#include <stdio.h>
void tneg(long num);
void tneg(long num)
{
int stillNeg = 0;
if (num < 0L) num = -num;
if (num < 0L) stillNeg = 1;
printf("%ld %s\n", num, (stillNeg)? " Still negative" : "");
}
int main(int argc, char ** argv)
{
long count;
long test, vtest, num, vnum;
printf("Function calls\n");
tneg((long)0x7ffffffe);
tneg((long)0x7fffffff);
tneg((long)0x80000000);
tneg((long)0x80000001);
tneg((long)0x80000002);
printf("For loop\n");
vnum = (argc == 5) ? 5 : 0x7ffffffe;
num = 0x7ffffffe;
for (count = 0; count < 5; count++)
{
int stillNeg = 0, vstillNeg = 0;
test = num; vtest = vnum;
if (test < 0) test = - test;
if (test < 0) stillNeg = 1;
if (vtest < 0) vtest = - vtest;
if (vtest < 0) vstillNeg = 1;
printf("num = %ld %s ", test, (stillNeg)? " neg" : " ");
printf("vnum = %ld %s\n", vtest, (vstillNeg)? " neg" : "");
num += 1; vnum += 1;
}
return 0;
}
without optimisation where overflow is involved.
I suspect this was "done to death" about 20 years ago, but
I can't find anything in comp.lang.c matching this. Is this
the "if you overflow the compiler can do whatever it likes"
clause?
The original problem I was trying to solve is why a simple
embedded "printf("%ld")" was printing random garbage when
handed -2147483648.
Here are the results for the following simple program with different
optimisation levels, in all cases "-O1" gives sane results and "-O2"
gives remarkably creative results.
The problems are:
1 - With "-O2" the second test in the following is optimised out:
as it "can't be true". Unless (num == -2147483648) in which
case it IS true, and is what I'm trying to correct for in
the function I was trying to fix.
if (num < 0L) num = -num;
if (num < 0L) stillNeg = 1;
2 - "-2147483647 + 1 == -2147483647" ???
3 - "-2147483647 == --2147483647" ???
This is the "sane" one without optimisation.
$ gcc --version
gcc (GCC) 4.3.4 20090804 (release) 1
$ gcc -Wall -O1 -o ox2 ox2.c
$ ./ox2
Function calls
2147483646
2147483647
-2147483648 Still negative
2147483647
2147483646
For loop
num = 2147483646 vnum = 2147483646
num = 2147483647 vnum = 2147483647
num = -2147483648 neg vnum = -2147483648 neg
num = 2147483647 vnum = 2147483647
num = 2147483646 vnum = 2147483646
This is the insane one with optimisation.
$ gcc -Wall -O2 -o ox2 ox2.c
$ ./ox2
Function calls
2147483646
2147483647
-2147483648 *** Missed the second test ***
2147483647
2147483646
For loop
num = 2147483646 vnum = 2147483646
num = 2147483647 vnum = 2147483647
num = 2147483647 vnum = -2147483648
num = 2147483647 vnum = -2147483647
num = 2147483647 vnum = -2147483646
^^ That got stuck ^^ ^^ That is negating when it shouldn't **
Here's the test code. Apologies for the "crammed style", I don't
usually write code that looks this bad:
#include <stdio.h>
void tneg(long num);
void tneg(long num)
{
int stillNeg = 0;
if (num < 0L) num = -num;
if (num < 0L) stillNeg = 1;
printf("%ld %s\n", num, (stillNeg)? " Still negative" : "");
}
int main(int argc, char ** argv)
{
long count;
long test, vtest, num, vnum;
printf("Function calls\n");
tneg((long)0x7ffffffe);
tneg((long)0x7fffffff);
tneg((long)0x80000000);
tneg((long)0x80000001);
tneg((long)0x80000002);
printf("For loop\n");
vnum = (argc == 5) ? 5 : 0x7ffffffe;
num = 0x7ffffffe;
for (count = 0; count < 5; count++)
{
int stillNeg = 0, vstillNeg = 0;
test = num; vtest = vnum;
if (test < 0) test = - test;
if (test < 0) stillNeg = 1;
if (vtest < 0) vtest = - vtest;
if (vtest < 0) vstillNeg = 1;
printf("num = %ld %s ", test, (stillNeg)? " neg" : " ");
printf("vnum = %ld %s\n", vtest, (vstillNeg)? " neg" : "");
num += 1; vnum += 1;
}
return 0;
}