'C' 语句如何在内存中执行
How do 'C' statements execute inside memory
假设我这里有这段 C 代码:
int main() {
int a = 10;
printf("test1");
printf("test2");
someFunc();
a = 20;
printf("%d",a);
}
好吧,我认为所有这些语句都是一次存储在堆栈中,然后一个一个地弹出以执行。我对么?如果不对,请指正。
不是真的没有。 C 标准没有提到 stack 所以你的想法是错误的。
只要遵循 C 标准,C 编译器(或解释器)就可以做任何它喜欢的事情。
在您的情况下,这可能意味着,(i) 完全删除 a
,因为它仅用于在函数末尾输出 20,以及 (ii) someFunc()
如果这样做没有副作用,可以删除。
通常发生的是您的代码被转换为适合目标体系结构的机器代码。尽管现代编译器会积极优化,但这些机器代码指令确实倾向于非常忠实地遵循代码(从这个意义上讲,C 相当"low level")。
值得注意的是,C 标准并不强制执行。因此,只要根据标准输出是正确的,编译器就可以自由选择实现它。
您最有可能发生的情况是,编译器将这段 C 代码翻译成汇编代码,然后从上到下执行。
a = 20;
除非您在其他地方使用它,否则很可能已被优化掉。好的编译器也会为你抛出警告:
Warning: Unused Variable a
C 标准没有指定内存中的位置。
然而,计算机通常是这样工作的:
- 你的程序由各种内存组成sections/segments,通常它们被称为
.data
、.bss
、.rodata
、.stack
、.text
并且可能还有 .heap
。 .text
部分用于存储实际的程序代码,其余部分用于存储变量。 More info on Wikipedia.
- C 代码由编译器翻译成机器代码(汇编程序)。所有代码都存储在
.text
部分,这是只读存储器。
- 现代计算机可以 "mark" 内存作为代码或数据,如果您尝试在数据部分执行代码或将代码部分视为数据,将能够生成硬件异常。通过这种方式,处理器可以协助捕获悬空指针或 运行-away 代码等错误。
- 理论上您可以从任何内存部分执行代码,甚至可以在堆栈上执行代码,但由于前面提到的功能,通常不会这样做。大多数情况下,无论如何这样做都没有任何意义。
因此对于您的特定代码片段,唯一存储在堆栈中的是变量 a
。或者更可能的是,出于性能原因,它存储在 CPU 寄存器中。
字符串文字 "test1"
、"test2"
和 "%d"
将存储在 .rodata
部分。
文字 20
可以存储在 .rodata
部分,或者更有可能合并到代码中,因此与其余代码一起存储在 .text
中。
程序计数器确定当前执行的代码部分。堆栈不涉及任何东西,它只是用于存储数据。
假设我这里有这段 C 代码:
int main() {
int a = 10;
printf("test1");
printf("test2");
someFunc();
a = 20;
printf("%d",a);
}
好吧,我认为所有这些语句都是一次存储在堆栈中,然后一个一个地弹出以执行。我对么?如果不对,请指正。
不是真的没有。 C 标准没有提到 stack 所以你的想法是错误的。
只要遵循 C 标准,C 编译器(或解释器)就可以做任何它喜欢的事情。
在您的情况下,这可能意味着,(i) 完全删除 a
,因为它仅用于在函数末尾输出 20,以及 (ii) someFunc()
如果这样做没有副作用,可以删除。
通常发生的是您的代码被转换为适合目标体系结构的机器代码。尽管现代编译器会积极优化,但这些机器代码指令确实倾向于非常忠实地遵循代码(从这个意义上讲,C 相当"low level")。
值得注意的是,C 标准并不强制执行。因此,只要根据标准输出是正确的,编译器就可以自由选择实现它。
您最有可能发生的情况是,编译器将这段 C 代码翻译成汇编代码,然后从上到下执行。
a = 20;
除非您在其他地方使用它,否则很可能已被优化掉。好的编译器也会为你抛出警告:
Warning: Unused Variable a
C 标准没有指定内存中的位置。
然而,计算机通常是这样工作的:
- 你的程序由各种内存组成sections/segments,通常它们被称为
.data
、.bss
、.rodata
、.stack
、.text
并且可能还有.heap
。.text
部分用于存储实际的程序代码,其余部分用于存储变量。 More info on Wikipedia. - C 代码由编译器翻译成机器代码(汇编程序)。所有代码都存储在
.text
部分,这是只读存储器。 - 现代计算机可以 "mark" 内存作为代码或数据,如果您尝试在数据部分执行代码或将代码部分视为数据,将能够生成硬件异常。通过这种方式,处理器可以协助捕获悬空指针或 运行-away 代码等错误。
- 理论上您可以从任何内存部分执行代码,甚至可以在堆栈上执行代码,但由于前面提到的功能,通常不会这样做。大多数情况下,无论如何这样做都没有任何意义。
因此对于您的特定代码片段,唯一存储在堆栈中的是变量 a
。或者更可能的是,出于性能原因,它存储在 CPU 寄存器中。
字符串文字 "test1"
、"test2"
和 "%d"
将存储在 .rodata
部分。
文字 20
可以存储在 .rodata
部分,或者更有可能合并到代码中,因此与其余代码一起存储在 .text
中。
程序计数器确定当前执行的代码部分。堆栈不涉及任何东西,它只是用于存储数据。