测试以下代码:
#include #include main() { const char *yytext="0"; const float f=(float)atof(yytext); size_t t = *((size_t*)&f); printf("t should be 0 but is %dn", t); }
编译它:
gcc -O3 test.c
GOOD输出应该是:
"t should be 0 but is 0"
但是使用我的gcc 4.1.3,我有:
"t should be 0 but is -1209357172"
使用编译器标志-fno-strict-aliasing。
启用严格别名,因为默认情况下至少为-O3,在行中:
size_t t = *((size_t*)&f);
编译器假定size_t *不指向与float *相同的内存区域。 据我所知,这是符合标准的行为(遵循ANSI标准中的严格别名规则开始围绕gcc-4,正如Thomas Kammeyer所指出的那样)。
如果我没记错的话,你可以使用一个中间强制转换为char *来解决这个问题。 (编译器假定char *可以别名)
换句话说,尝试这个(现在不能自己测试,但我认为它会起作用):
size_t t = *((size_t*)(char*)&f);
在C99标准中,6.5-7中的以下规则涵盖了这一点:
对象的存储值只能由具有以下类型之一的左值表达式访问:73)
最后一项是为什么先铸造(char *)的原因。
根据指针别名的C99规则,不再允许这样做。 两种不同类型的指针不能指向内存中的相同位置。 此规则的例外是void和char指针。
因此,在您转换为size_t指针的代码中,编译器可以选择忽略它。 如果你想将float值作为size_t得到,只需指定它,浮动将被转换(截断而不是舍入),如下所示:
size_t size =(size_t)(f); //这个有效
这通常被报告为一个错误,但事实上它确实是一个允许优化器更有效地工作的function。
在gcc中,您可以使用编译器开关禁用它。 我相信-fno_strict_aliasing。
这是不好的C代码:-)
有问题的部分是你通过将一个对象转换为一个整数指针并取消引用它来访问一个float类型的对象。
这会破坏别名规则。 编译器可以自由地假设指向不同类型的指针(如float或int)在内存中不重叠。 你完全是这样做的。
编译器看到的是你计算的东西,将它存储在浮点数f中并且永远不再访问它。 很可能编译器已经删除了部分代码,并且从未发生过赋值。
通过size_t指针解除引用将在这种情况下从堆栈返回一些未初始化的垃圾。
你可以做两件事来解决这个问题:
为什么你认为t应该是0?
或者,准确地说,“为什么你会认为浮点零的二进制表示与整数零的二进制表示相同?”
这是糟糕的C代码。 您的强制转换会破坏C别名规则,并且优化器可以自由地执行破坏此代码的操作。 您可能会发现GCC已经在浮点写入之前调整了size_t读取(以隐藏fp管道延迟)。
您可以设置-fno-strict-aliasing开关,或使用union或reinterpret_cast以符合标准的方式重新解释该值。
除了指针对齐,你期望sizeof(size_t)== sizeof(float)。 我不认为它(在64位Linux size_t应该是64位但浮动32位),这意味着你的代码将读取未初始化的东西。
-O3不被视为“理智”,-O2通常是上限,除了某些多媒体应用程序。
有些应用程序甚至无法走得那么远,如果你超越-O1就会死掉。
如果你有一个足够新的GCC(我在4.3这里),它可能支持这个命令
gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts
如果你小心,你可能会通过该列表找到你正在启用的给定的单一优化导致这个错误。
来自man gcc
:
The output is sensitive to the effects of previous command line options, so for example it is possible to find out which optimizations are enabled at -O2 by using: -O2 --help=optimizers Alternatively you can discover which binary optimizations are enabled by -O3 by using: gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts diff /tmp/O2-opts /tmp/O3-opts | grep enabled
我测试了你的代码:“i686-apple-darwin9-gcc-4.0.1(GCC)4.0.1(Apple Inc. build 5465)”
而且没有问题。 输出:
t should be 0 but is 0
所以你的代码中没有错误。 这并不意味着它是好的代码。 但我会添加主函数的返回类型和“返回0”; 在function的最后。
需要了解更多c/c++开发分享我有gcc优化错误或C代码问题吗?,也可以关注C/ C++技术分享栏目—计算机技术网(www.ctvol.com)!
以上就是c/c++开发分享我有gcc优化错误或C代码问题吗?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/980579.html