Description of problem: if '-O2' is specified as gcc option, the result of arithmetic operation using 'double' type is different from '-O1' and no option. Version-Release number of selected component (if applicable): gcc-3.4.3-9.EL4 How reproducible: always Steps to Reproduce: 1. # gcc -test1.c -o test1_o2 -O2 2. # gcc -test1.c -o test1_o1 -O1 3. # gcc -test1.c -o test1 4. # ./test1_o2 5. # ./test1_o1 6. # ./test1 Actual results: # uname -a Linux xxxxx 2.6.9-5.0.3.EL #1 SMP Mon Feb 14 09:52:53 EST 2005 ia64 ia64 ia64 GNU/Linux # ./test1_o2 fx.fract = 0x1 fx.value = 0x0 # ./test1_o1 fx.fract = 0x74BC fx.value = 0x7B # ./test1 fx.fract = 0x74BC fx.value = 0x7B ( the result of '-O2' is different from others. ) Expected results: # ./test1_o2 fx.fract = 0x74BC fx.value = 0x7B ( the result of '-O2' is same as others. ) Additional info: - if we compile test1.c on RHEL4 GA for x86, the result of '-O2' is same as otheres. # uname -a Linux xxxxx 2.6.9-5.ELsmp #1 SMP Wed Jan 5 19:30:39 EST 2005 i686 i686 i386 GNU/Linux # gcc test1.c -o test1_o2 -O2 # ./test1_o2 fx.fract = 0x74BC fx.value = 0x7B - if we add printf(3) in fuction '__qgf_ttac_fixed_from_double()' in test1.c, the results are different from its place. 2) 1) add printf(3) before operation 'n = (int) (d * 65536L);' -------------------------------------------------------------- ï¼ FIXED __qgf_ttac_fixed_from_double(double d) { int n; printf("\n"); n = (int) (d * 65536L); return *(FIXED *)&n; } ï¼ -------------------------------------------------------------- # gcc test2.c -o test2_o2 -O2 # ./test2_o2 fx.fract = 0x0 fx.value = 0x0 2) add printf(3) after operation 'n = (int) (d * 65536L);' -------------------------------------------------------------- ï¼ FIXED __qgf_ttac_fixed_from_double(double d) { int n; n = (int) (d * 65536L); printf("\n"); return *(FIXED *)&n; } ï¼ -------------------------------------------------------------- # gcc test3.c -o test3_o2 -O2 # ./test3_o2 fx.fract = 0x74BC fx.value = 0x7B
I couldn't attach the testcase. The following is the testcase. // ***** test1.c ***** // #include <stdio.h> typedef struct _FIXED { unsigned short fract; short value; } FIXED, *LPFIXED; FIXED __qgf_ttac_fixed_from_double(double); FIXED __qgf_ttac_fixed_from_double(double d) { int n; n = (int) (d * 65536L); return *(FIXED *)&n; } int main(int argc, char *argv[]) { FIXED fx; double db; db = 123.456; fx = __qgf_ttac_fixed_from_double(db); printf("\nfx.fract = 0x%X\n", fx.fract); printf("fx.value = 0x%X\n\n", fx.value); }
This testcase violates ISO C99 6.5 aliasing rules and therefore triggers undefined behaviour. See either the standard, or info gcc on -fstrict-aliasing which is the default for -O2 and above. You can use a union to access the value through it, or to work around buggy code you can build with -fno-strict-aliasing. BTW, if you compile this testcase with -Wall, which you always should do, the compiler warns about this: /tmp/149971.c: In function `__qgf_ttac_fixed_from_double': /tmp/149971.c:16: warning: dereferencing type-punned pointer will break strict-aliasing rules /tmp/149971.c: In function `main': /tmp/149971.c:31: warning: control reaches end of non-void function