0
#include <stdio.h>
#include <math.h>

int main(int argc, const char *argv[])
{
  long i, max;
  long sum = 0;
  max = (long)pow(2,32);

  for (i = 0; i < max; i++) {
    sum += i; 
  }
  printf("%ld\n", sum);
  return 0;
}

$gcc -S main.c

问题是:在下面的.L2代码中,-8(%rbp)总是等于零,并且%rax总是大于零。所以这是一个无限循环?如果我用 编译gcc -S -O1 main.c,那就很清楚了。我真的很困扰!

只是汇编代码的一小部分:

main:   
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $48, %rsp
    movl    %edi, -36(%rbp)
    movq    %rsi, -48(%rbp)
    movq    $0, -16(%rbp)
    movl    $0, -8(%rbp)
    movl    $2, -4(%rbp)
    movq    $0, -24(%rbp)
    jmp .L2

.L3:
    movq    -24(%rbp), %rax
    addq    %rax, -16(%rbp)
    addq    $1, -24(%rbp)

.L2:
    movq    -24(%rbp), %rax     
    cmpq    -8(%rbp), %rax       
    jl  .L3                      

.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
4

2 回答 2

2

真正的循环计数器 ( i) 位于-24(%rbp)。在第三行,它增加了。在第 4 行,它被加载到rax. 所以rax不是一个常数零,它与 一起贯穿值i

-8(%rbp),一个假设,是在哪里max。因此,将 的值与之进行i比较,这就是您的循环退出条件。-8(%rbp)不应为零。如果是的话,我会闻到流氓 32 位算术的味道。

编辑:我想我知道怎么了。常数 2 和 32 是int,不是long,因此假定为 32 位。大小int取决于平台;甚至 GCC 的约定也可能会有所不同。pow(int, int)被实现为内在的。当参数为 32 位时,2^32 为 0。

代替

max = (long)pow(2,32);

max = pow(2l, 32l);

或者使用常数更好:

max = 0x100000000l;

就像我和其他人所怀疑的那样,混合中有一块 32 位。

于 2013-11-07T17:49:43.253 回答
1

不,这不是无限循环。首先 %rax 并不总是大于 0,在该行中它从 -24(%rbp) 中获取值,这显然是可变i的。当它进入循环时,它将 -24(%rbp) 设置为零,然后跳转到 .L2 它发生的部分原因是您没有显示。如果变量的值 -8(%rbp)max等于零(在溢出的情况下)jl将不会跳转到 .L3 并且循环将在第一次检查后终止。我不太明白为什么你需要为此阅读汇编,这从 C++ 源代码中很明显。

于 2013-11-07T17:46:30.007 回答