写点什么

一次编译器优化的陷阱

  • 2025-11-21
    北京
  • 本文字数:844 字

    阅读完需:约 3 分钟

本文分享自天翼云开发者社区《一次编译器优化的陷阱》.作者:江****禄

某次问题排查,最终隐掉完所有业务逻辑后, 化简为如下的简单代码:


来看一下,这个的 bcount is zero 会打印吗?


#include <time.h>#include <stdio.h>#include <stdlib.h>#include <cstring>#include <string.h>#include <unistd.h>
intmain(void){ int bcount = 2;
while (bcount < 1296005092) { if (bcount < 1296005092) { printf("b %lld (%d)%x is < than %lld\n",bcount,bcount, bcount,1296005092); } else { printf("b %lld (%d)%x is >= than %lld\n",bcount,bcount,bcount, 1296005092); } sleep(1);
if (bcount == 0) { printf("bcount is zero\r\n"); return -1; } bcount *= 2; }
return 0;}
复制代码


这个 demo 代码的逻辑为:


while 循环中比较 bcount 与 1296005092 的大小,当 bcount >=1296005092 或者 bcount 为 0,结束循环。


使用 gcc -O2 优化编译后,查看 demo 程序的输出如下,可以看到,会导致一直在 while 死循环, 原因是 bcount 为 int 。 然后待比较的那个数 刚好卡


在一个区间,具体如下:当 bcount ==0x80000000 时候,bcount 最高位为 1, 这样该数为负数,小于待比较的数 1296005092,注意:


上一次循环中,由于上一个值 0x40000000 的时候刚好比 1296005092 小,然后此次循环结果为负数,而下一个循环这个 int 溢出结果为 0 ,所以一直


卡在这里。那么问题就变成了:其中的 bcount==0 不会生效??


使用-O1 编译后,查看 demo 代码的输出如下, 可以看到 while 循环中可以判断到 bcount 为 0.


结论

简化代码,对比两者汇编代码的区别如下,


可以看到在 gcc 的 O2 优化等级上,如果是乘 2 运算,优化后的代码认为结果不应该为 0。


到此为止,这里如果将代码中的 bcount 乘 2 运算,替换为左移一位,在 O2 模式下编译,while 循环也可以正常退出。


这里应该是 gcc 的 O2 等级以上优化逻辑有 bug,在整数乘法运算下,编译器认为不可能出现结果为 0,将代码中与 0 的判断优化掉,导致优化后的代码逻辑不符合预期。


用户头像

还未添加个人签名 2022-02-22 加入

天翼云是中国电信倾力打造的云服务品牌,致力于成为领先的云计算服务提供商。提供云主机、CDN、云电脑、大数据及AI等全线产品和场景化解决方案。

评论

发布
暂无评论
一次编译器优化的陷阱_CDN_天翼云开发者社区_InfoQ写作社区