让我们说我有一个数组
int aVar[10];
...
...
for(i=0; i<10; i++)
aVar[i] = i*10;
在这里,我所知道的是,数组被引用为指针,索引值的位置使用类似于(base address of aVar) + sizeof(int) * i
的方式计算。如果我错了,请纠正我。
我的问题:
这个计算在运行可执行文件之前是否已由编译器完成,或者这个算术计算是在执行时在数组中找到确切的位置?
当然,我们无法在编译时获取aVar
的地址。
答案 0 :(得分:4)
“当然我们在编译时无法获取aVar的地址?”
是的,实际上,我们可以或足够近。如果它是全局的或静态的,那么它将占据链接器可以解析的固定位置 - 不是完全编译时间而是在运行时。如果它在堆栈中,堆栈指针的偏移在编译时是已知的,因此不需要在机器(例如PC)上计算任何地址,其中地址可以采用表格偏移+寄存器的内容。
答案 1 :(得分: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.
答案 2 :(得分: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下降零开始计算。由于减法通常会在广泛使用的机器中生成条件代码,因此可以保存比较指令。)