在技术面试中有人问我这个问题 “ c语言中的编译过程是什么?”
我回答:
然后他继续
“”然后是这些编译过程中的一个,程序中的所有变量都位于并具有地址....如果有2个变量A和B ....之后,过程A和B将进行在内存中有地址”
(我认为他的意思是每个过程后生成了哪个文件)
我最后回答说,是在链接器之后,因为需要定义外部值,但是我不知道我说的是对还是错。
所以希望有人可以帮助我理解这个问题
答案 0 :(得分:2)
我只想对user3386109注释添加一些说明:
希望有帮助。
答案 1 :(得分:-1)
没有人回答地址问题。根据平台的不同,您的变量可能有多个地址。
根据变量进行编译时,要么为堆栈上的堆栈指针分配了一个偏移量,但是直到该函数运行时(通常)才知道堆栈指针。对于.data和.bss,编译器将保留一种机制,具体取决于编译器和目标如何到达变量。
unsigned int x = 5;
unsigned int y;
unsigned int more_fun ( unsigned int );
unsigned int fun ( unsigned int z )
{
unsigned int a;
a = x + 1;
a = a + more_fun(y) + y + z;
return(a);
}
00000000 <fun>:
0: e92d4070 push {r4, r5, r6, lr}
4: e1a06000 mov r6, r0
8: e59f3028 ldr r3, [pc, #40] ; 38 <fun+0x38>
c: e5934000 ldr r4, [r3]
10: e59f5024 ldr r5, [pc, #36] ; 3c <fun+0x3c>
14: e5950000 ldr r0, [r5]
18: ebfffffe bl 0 <more_fun>
1c: e5953000 ldr r3, [r5]
20: e0844003 add r4, r4, r3
24: e2844001 add r4, r4, #1
28: e0844006 add r4, r4, r6
2c: e0840000 add r0, r4, r0
30: e8bd4070 pop {r4, r5, r6, lr}
34: e12fff1e bx lr
在这种情况下,z不存储在堆栈中,而是将寄存器保存在堆栈中,并且z存储在该寄存器中,因此它没有相对或其他地址。 x和y确实有地址供链接器稍后填充,这是此编译器和目标如何解决该问题的方法。这显然是优化的。 a没有地址,也没有在寄存器中处理。如果我没有优化,那么a和z将具有堆栈指针相对存储,并且全局变量保持全局状态。
但是一旦链接。
00200008 <more_fun>:
200008: e12fff1e bx lr
0020000c <fun>:
20000c: e92d4070 push {r4, r5, r6, lr}
200010: e1a06000 mov r6, r0
200014: e59f3028 ldr r3, [pc, #40] ; 200044 <fun+0x38>
200018: e5934000 ldr r4, [r3]
20001c: e59f5024 ldr r5, [pc, #36] ; 200048 <fun+0x3c>
200020: e5950000 ldr r0, [r5]
200024: ebfffff7 bl 200008 <more_fun>
200028: e5953000 ldr r3, [r5]
20002c: e0844003 add r4, r4, r3
200030: e2844001 add r4, r4, #1
200034: e0844006 add r4, r4, r6
200038: e0840000 add r0, r4, r0
20003c: e8bd4070 pop {r4, r5, r6, lr}
200040: e12fff1e bx lr
200044: 0021004c eoreq r0, r1, r12, asr #32
200048: 00210050 eoreq r0, r1, r0, asr r0
Disassembly of section .data:
0021004c <x>:
21004c: 00000005 andeq r0, r0, r5
Disassembly of section .bss:
00210050 <y>:
210050: 00000000 andeq r0, r0, r0
x和y具有已知/固定地址。因此,当您在此处看到答案或评论时,他们会说的是链接时间。在这种情况下,编译器最终不需要任何基于堆栈的变量,从技术上讲,这些变量将是运行时的,尽管使用了一个简单的程序,并说只能对函数进行一次调用,并且可以预先确定和/或最终将其固定下来。链接时间确定了它们的结局,但不要假设,非静态本地变量是在运行时从技术上确定的。
现在,我已经使用-fPIC进行了构建,对x和y的访问将是双重间接的,将读取全局偏移表,然后在其中读取变量本身的地址。初始地址在链接时确定,但可以在加载时修改为其他位置。
然后是虚拟的还是物理的,如果您在操作系统上运行,可以这样说,但不一定,但是可能使用mmu允许程序认为它在某个基于零的内存空间中(程序加载在偏移处) (对于程序和工具链而言,则说0x8000),但是有一个物理地址会因每次负载而有所不同,甚至更糟糕的是,如果换出了程序,只要正确处理了虚拟空间,它就有可能返回其他地方如果换出,则物理在加载时或运行时可能会有所不同。
当您在面试或大学考试中看到这样的问题时,就是这个问题。有时,询问者正在寻找特定的答案,例如链接器,虽然在很多情况下都适用,但也有例外。或者也许被问到的人知道的不仅仅是危险,而且正在寻找加载时间,链接时间或运行时间,或者正在寻找更长的解释。
到目前为止,这些答案还有其他例外。因此,被询问的人很可能对这个问题有一个特定的答案或原因,这很可能是您无法理解他们的想法并使其正确。所以这是一个不公平/不好的问题,我会为在这样一个糟糕的问题上工作的地方而犹豫。除非是后者,否则他们知道所有细微差别,并试图查看您是否出于某种原因知道所有细微差别。看看谁跌倒了,可能与他们的产品或开发无关,这可能是一个淘汰的问题。
我建议您为一些不同的gnu支持的目标(例如pdp-11,而不是在开玩笑,arm,x86等)构建/构建一些交叉编译器,尝试上述类似的不同实验,或者反汇编您的实际项目正在研究该工具的工作原理。如果在面试中有自由,您可以说,让我展示给您,然后带上笔记本电脑,敲出一个简单的例子,如果他们没有跟着您而感到困惑,请说声谢谢并寻找其他雇主。同时,我们整天进行面试,其中几个人与候选人一一轮换,当我们在岗位上聆听时,我问这个问题,这就是他们的答案。房间里的其他人说:“我什至都不知道你想在那儿问什么”,所以有时候这只是一个不好的问题。
我无法想象什么样的工作真正关心这样的事情,为什么这是一个相关的面试问题?这是一个工具链开发人员吗?
编辑
简短答案:有多个正确答案,同时这意味着答案可能彼此矛盾。
确定本地项目的编译时堆栈指针相对偏移量。但是堆栈指针本身以及偏移量是该函数的运行时事物。
链接时间地址应用于包括变量在内的其余项目。因此,链接时间是正确的答案。
可以更改加载时间,例如与位置无关的代码,因此加载时间是正确的答案。
当然还有虚拟地址和物理地址,mmu后面的物理地址在加载时,并且有可能在运行时更改。