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