未注释未使用的语句时浮点异常?

Jam*_*at7 8 c floating-point gcc compiler-errors

当运行如下所示的程序时,它会产生ok输出:

 j=         0    9007199616606190.000000 = x
 k=         0    9007199616606190.000000 = [x]
 r=  31443101                   0.000000 = m*(x-[x]) 
Run Code Online (Sandbox Code Playgroud)

但是当注释掉的行( //if (argc>1) r = atol(argv[1]);)被取消注释时,它会产生:

 j=     20000    9007199616606190.000000 = x
 k=     17285    9007199616606190.000000 = [x]
 r=  31443101                   0.000000 = m*(x-[x]) 
Run Code Online (Sandbox Code Playgroud)

即使该行应该没有效果,因为argc>1是假的.有没有人对这个问题有合理的解释?它是否可以在任何其他系统上重现?

 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
 int main(int argc, char *argv[]) {
   int  j, k, m=10000;
   double r=31443101, jroot=sqrt(83), x;
   //if (argc>1) r = atol(argv[1]);
   x = r * r * jroot;
   j = m*(x-floor(x));
   k = floor(m*(x-floor(x)));
   printf ("j= %9d   %24.6f = x\n", j, x);
   printf ("k= %9d   %24.6f = [x]\n", k, floor(x));
   printf ("r= %9.0f   %24.6f = m*(x-[x]) \n", r, m*(x-floor(x))); 
   return 0;
 }
Run Code Online (Sandbox Code Playgroud)

注意,测试系统=带有Linux 2.6.35.14-96.fc14.i686的AMD Athlon 64 5200+系统(,在64位硬件上启动以运行32位操作系统)与gcc(GCC)4.5.1 20100924(红色帽子4.5.1-4)

更新 -几个小时前我发布了一条评论,即使用和不使用if语句生成的代码仅在堆栈偏移和一些跳过的代码中有所不同.我现在发现评论并不完全正确; 对于非优化代码是正确的,但对于我执行的-O3代码则不然.

优化开关对问题的影响:

  • -O0:两个程序版本运行正常
  • -O2或-O3:带注释的版本上面有错误,其中j=20000k=17285
  • -O1:带注释的版本有j=20000(错误)和k=0(OK)

无论如何,看看-O3 -S代码清单,这两种情况大多不同于跳过的if代码和堆栈偏移直到之前的行call floor,此时if-if代码fstpl比without-if代码多一个:

    ...  ;; code without comment:
fmul    %st, %st(1)
fxch    %st(1)
fstpl   (%esp)
fxch    %st(1)
fstpl   48(%esp)
fstpl   32(%esp)
call    floor
movl    $.LC2, (%esp)
fnstcw  86(%esp)
movzwl  86(%esp), %eax
    ...
    ...  ;; versus code with comment:
fmul    %st, %st(1)
fxch    %st(1)
fstpl   (%esp)
fxch    %st(1)
fstpl   48(%esp)
fstpl   32(%esp)
fstpl   64(%esp)
call    floor
movl    $.LC3, (%esp)
fnstcw  102(%esp)
movzwl  102(%esp), %eax
    ...
Run Code Online (Sandbox Code Playgroud)

我还没弄清楚差异的原因.

pax*_*blo 3

在我的系统上没有重复,Win7 运行带有 gcc 4.3.4 的 CygWin。无论有没有该if语句, 的值j都设置为零,而不是 20K。

我唯一的建议是使用它gcc -S来查看汇编器输出。这应该能告诉你出了什么问题。

具体来说,将汇编器输出生成到两个单独的文件,每个文件对应工作变体和非工作变体,然后 vgrep 它们(并排观察它们)以尝试确定差异。


顺便说一句,这在您的环境中是一个严重的失败。m10000 意味着必须等于x - floor(x)2。我一生都想不出任何实数会出现这种情况:-)