Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I have a gcc optimization bug or a C code problem?

Tags:

c

gcc

Test the following code:

#include <stdio.h>
#include <stdlib.h>
main()
{
    const char *yytext="0";
    const float f=(float)atof(yytext);
    size_t t = *((size_t*)&f);
    printf("t should be 0 but is %d\n", t);
}

Compile it with:

gcc -O3 test.c

The GOOD output should be:

"t should be 0 but is 0"

But with my gcc 4.1.3, I have:

"t should be 0 but is -1209357172"
like image 550
acemtp Avatar asked Sep 17 '08 14:09

acemtp


People also ask

How do I stop GCC optimization?

The gcc option -O enables different levels of optimization. Use -O0 to disable them and use -S to output assembly.

Is GCC an optimizing compiler?

GCC performs nearly all supported optimizations that do not involve a space-speed tradeoff. As compared to -O , this option increases both compilation time and the performance of the generated code.

How do I find optimized code?

you can get an idea of optimization using the option -fdump-tree-optimized with gcc . and you'll get an optimised file. you cannot run the code but using that you can get an idea of optimization . dont forget to include -O2 or -O3 or some other level.

What is GCC optimize?

The compiler optimizes to reduce the size of the binary instead of execution speed. If you do not specify an optimization option, gcc attempts to reduce the compilation time and to make debugging always yield the result expected from reading the source code.


2 Answers

Use the compiler flag -fno-strict-aliasing.

With strict aliasing enabled, as it is by default for at least -O3, in the line:

size_t t = *((size_t*)&f);

the compiler assumes that the size_t* does NOT point to the same memory area as the float*. As far as I know, this is standards-compliant behaviour (adherence with strict aliasing rules in the ANSI standard start around gcc-4, as Thomas Kammeyer pointed out).

If I recall correctly, you can use an intermediate cast to char* to get around this. (compiler assumes char* can alias anything)

In other words, try this (can't test it myself right now but I think it will work):

size_t t = *((size_t*)(char*)&f);
like image 73
Tobi Avatar answered Sep 29 '22 14:09

Tobi


In the C99 standard, this is covered by the following rule in 6.5-7:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:73)

  • a type compatible with the effective type of the object,

  • a qualified version of a type compatible with the effective type of the object,

  • a type that is the signed or unsigned type corresponding to the effective type of the object,

  • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,

  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or

  • a character type.

The last item is why casting first to a (char*) works.

like image 20
Michael Burr Avatar answered Sep 29 '22 16:09

Michael Burr