1

假设我有一个数组

int aVar[10];
...
...
for(i=0; i<10; i++)
    aVar[i] = i*10;

在这里,我所知道的是数组被引用为指针,索引值的位置是用类似的东西计算出来的(base address of aVar) + sizeof(int) * i:如果我错了,请纠正我。

我的问题:

在运行可执行文件之前编译器是否已经完成了这个计算,或者在执行时完成了在数组中查找确切位置的算术计算?

当然,我们无法aVar在编译时得到地址。

4

3 回答 3

4

“当然我们不能在编译时得到aVar的地址?”

是的,实际上,我们可以,或者说足够接近。如果它是全局的或静态的,那么它将占据链接器可以解析的固定位置——不是在编译时而是在运行时。如果它在堆栈上,则堆栈指针的偏移量在编译时是已知的,因此在地址可以采用偏移量 + 寄存器内容形式的机器(例如 PC)上不需要计算任何内容。

于 2012-06-28T10:13:52.037 回答
2

名义上它是在运行时完成的,但标准并不关心结果是否正确(标准将此称为“as-if”规则)。这取决于编写 C 实现的人,并且可能取决于您使用的优化选项。

如果编译器展开循环,那么它将知道堆栈指针的偏移量aVar[0]aVar[1],就像它知道aVar堆栈指针的偏移量一样。因此,看起来像这样的代码没有不可避免的障碍:

store 0 at some constant offset from the stack pointer
store 10 at a slightly larger constant offset from the stack pointer
etc.
于 2012-06-28T10:03:25.967 回答
0

“无法在编译时获取 aVar 的地址”。没错,但是编译器可以在进入循环之前生成代码来计算其地址,并且在性能方面它需要优化的循环体,而不是循环前代码。

一个好的编译器对此进行优化,要么将该基地址放入循环内的寄存器中,因此它不必重新获取它,或者注意到您的数组访问以与索引相同的方式扫描数组。一个非常聪明的编译器会意识到 i*10 是根据数组索引计算得出的,并且没有其他内容,并且也会替换索引。所以编译出来的优化代码大概更像:

int aVar[10];
...
...
register int* p = &aVar;  // my C syntax may be slight wrong here
for(i=0; i10<10*10; i10+=10)
    *p = i10;

(循环也可以反转,因此 i10 可以从 100 计数到零。由于减法通常在广泛使用的机器中产生条件代码,这可以节省比较指令。)

于 2012-06-28T10:51:42.683 回答