0

对于此代码:

int main(void) {
  int a = 1;
  int b = 2;
  int* pa = &a;
  *pa = a + b;
  printf("%d", a);
}

在编译时,编译器计算它需要多少空间。我们有 2 个整数和 1 个指针。所以它是2*4 + 8 = 16。然后它指定给定变量的内存相对于起始点地址的位置。 pa位于起点地址,长度为 8 个字节。 b位于起点地址 + 8 个字节,长度为 4 个字节。 a位于起点地址 + 12 个字节,长度为 4 个字节。

然后 go 指令执行时间:

  1. 要求操作系统分配 16 个字节并提供内存中该空间的地址。这将是起点地址。
  2. 将 的二进制表示1放在 的位置a
  3. 将 的二进制表示2放在 的位置b
  4. a将(起点地址 + 12 字节)的相对地址转换为其绝对位置,并将其放在pa.
  5. 获取 locationa处的字节和 location 处的字节b,添加它们,然后获取 location 处的字节pa。使用位置的字节pa作为地址并将计算的总和放在那里。
  6. 打印位置处的字节,a首先将它们转换为十进制数。
  7. 释放内存并让操作系统知道该程序已完成。

这是一个有效的翻译吗?

编辑:

假设使用了一个超级简单的编译器(没有优化)。它只关心 C 代码的有效执行。

4

3 回答 3

4

这几乎是翻译它的一种方法(a),尽管函数的局部变量通常在堆栈上分配,而不是要求操作系统提供一些内存来存储它们。

当然,使用智能编译器,源代码中有足够的信息可以简单地将整个事情优化为:

int main(void) { putchar('3'); }

(a) ISO C 标准没有规定事情是如何在幕后完成的,只是规定了它们以某种方式表现。将 C 视为实现该标准的虚拟机。虚拟机如何做并不真正相关,当然除了行为之外没有任何强制要求。

于 2018-09-05T09:51:56.170 回答
3

据我阅读,是的,这是一个有效的翻译。不,它几乎 100% 肯定不是您的编译器要生成的翻译。C 标准有所谓的as-if 规则,这意味着编译器可以自由生成任何程序,其副作用就像程序是为所谓的抽象 C 机器编译并在其中运行一样。

实际上,编译器可以例如生成以下程序:

  • 将整数'3'放入用作函数调用中的第一个参数的寄存器中
  • 称呼putchar
  • 将用作返回值的寄存器归零
  • main函数返回

对于观察者来说,这个程序的副作用与你的程序没有什么区别:它打印3并从mainwith0作为返回值返回。

于 2018-09-05T09:55:36.503 回答
1

步骤 1变量a,bpa将被分配到堆栈中。因此,不会向操作系统请求内存分配——您只需使用由进程本身控制的堆栈。也许它不会要求 16 个字节 - 4 个字节就足够了,因为您正在有效地使用 variable a。甚至那个是恒定的,所以实例a可以替换为1

第 4 步:编译器可能会完全跳过此步骤,因为pa在下一步重新分配之前,您不会使用 的值。

第 6 步:将两个参数(%d\0字符串和值1)压入堆栈并调用名为 的函数printf。不知道它是否输出到终端——也许stdout是重定向到一个文件中?

最后,不可能确切地知道该源代码会产生什么指令。取决于架构、操作系统/OS 版本、编译器/cc 版本、编译器标志...

于 2018-09-05T09:55:56.723 回答