对于此代码:
int main(void) {
int a = 1;
int b = 2;
int* pa = &a;
*pa = a + b;
printf("%d", a);
}
在编译时,编译器计算它需要多少空间。我们有2个整数和一个指针。所以它是2*4 + 8 = 16
。然后它指定给定变量的内存相对于起始点地址的位置。 pa
位于起始点地址,长度为8个字节。 b
位于起始点地址+8个字节,长度为4个字节。 a
位于起始点地址+ 12个字节,长度为4个字节。
然后去执行时间的说明:
1
的二进制表示放在a
的位置。2
的二进制表示放在b
的位置。a
(起始点地址+12字节)的相对地址转换为其绝对位置,并将其放在pa
的位置。a
的字节和位置b
的字节,添加它们然后在位置pa
获取字节。在位置pa
处使用字节作为地址并将计算的总和放在那里。a
的字节,首先将它们转换为十进制数。这是一个有效的翻译吗?
我们假设使用了一个超级简单的编译器(没有优化)。它所关心的只是C代码的有效执行。
据我所知,是的,这是一个有效的翻译。不,几乎100%肯定不是您的编译器将要生成的翻译。 C标准具有所谓的as-if rule,这意味着编译器可以自由地生成任何程序,其副作用就像程序是为所谓的抽象C机器编译并在那里运行一样。
实际上,编译器可以例如生成以下程序:
'3'
放入用作函数调用中第一个参数的寄存器中putchar
main
函数返回对于一个观察者来说,这个程序的副作用与你的程序无法区分:它打印3
并从main
返回,并以0
作为返回值。
这几乎是翻译它的一种方法(a),虽然函数的局部变量通常在堆栈上分配,而不是要求操作系统存储一些内存。
当然,使用智能编译器,源代码中有足够的信息可以简单地优化整个内容:
int main(void) { putchar('3'); }
(a)ISO C标准没有规定如何在幕后完成任务,只是它们以某种方式表现。将C视为实现标准的虚拟机。虚拟机如何实现它并不是真正相关的,当然也不是以行为之外的任何方式强制执行。
步骤1变量a
,b
和pa
将在堆栈中分配。因此,没有请求操作系统进行内存分配 - 您只需使用由进程本身控制的堆栈。也许它不会要求16个字节 - 4个字节就足够了,因为你有效地使用变量a
。即使那个是恒定的,所以a
的实例可以被1
取代。
步骤4:编译器可以完全跳过此步骤,因为在下一步中重新分配之前,您没有使用pa
的值。
步骤6:将两个参数(%d\0
字符串和值1
)推入堆栈并调用名为printf
的函数。不知道它是否输出到终端 - 也许stdout
重定向到文件?
最后,不可能确切地知道将从该源代码生成什么指令。取决于架构,操作系统/操作系统版本,编译器/ cc版本,编译器标志......