【问题标题】:Where the result of function call is kept if I pass it as parameter?如果我将函数调用的结果作为参数传递,它会保存在哪里?
【发布时间】:2021-08-19 11:57:58
【问题描述】:
uint32_t sum_a_b(uint32_t a, uint32_t b) {
    return a + b; 
}

uint32_t mul_c_d(uint32_t c, uint32_t d) {
    return c * d; 
}

int main(uint16_t argc, char **argv) {
    uint32_t e;
    e = mul_c_d(116, sum_a_b(17, 992));
    return 0;
}

问题是正在运行的机器在将调用sum_a_b(17, 992) 的结果作为第二个参数传递给mul_c_d 之前将其存储在哪里?

堆栈中有一些“临时变量”?

处理器寄存器?堆?

我在哪里可以阅读到这方面的信息?

与显式使用变量的任何区别,

int main(uint16_t argc, char **argv) {
    uint32_t e, t;
    t = sum_a_b(17, 992);
    e = mul_c_d(116, t);
    return 0;
}

??

不幸的是我没有足够的asm/disasm技能来直接检查它....

谢谢!!

【问题讨论】:

  • 我猜,因为它是一个uint32 返回类型,在大多数架构和编译器上,它将纯粹保存在累加器寄存器中。并且通常为 mul_c_d 调用压入堆栈,具体取决于编译器优化。
  • 这取决于编译器和“应用程序二进制接口”(ABI)。但是考虑到mul_c_d 调用的结果在分配给e 之前存储在某处,就像任何子表达式在用于外部表达式之前的结果一样(至少在抽象意义上)。此类存储位置是匿名的,可以是寄存器或内存。
  • 至于使用变量存储中间值。它可能会或可能不会被编译器优化,这可能取决于为编译器选择的优化级别。

标签: c stack heap-memory c99 cpu-registers


【解决方案1】:

C 标准没有指定变量和值的存储位置,因此结果将非常特定于系统。

“堆栈中有一些“临时变量”?可能。
“处理器寄存器?”可能。
“堆?”不,只有在显式调用 malloc 或等效函数时才使用堆。没有已知的 C 编译器隐式使用堆。

很遗憾我没有足够的 asm / disasm 技能来直接检查它

您不需要了解很多汇编程序就可以做到这一点。只需将你的代码扔进https://godbolt.org/,禁用优化,这就是你得到的(x86):

    mov     esi, 992
    mov     edi, 17
    call    sum_a_b
    mov     esi, eax
    mov     edi, 116
    call    mul_c_d

现在我们唯一需要知道的汇编程序是像mov 这样的指令将结果存储在左操作数中。这就是为什么memcpystrcpy 等 C 函数也将它们的结果存储在左操作数中的原因。

那么我们需要知道 esi、edi 和 eax 是 x86 上的寄存器。因此它将 992 和 17 存储在寄存器中,然后调用该函数。之后,它会从第三个寄存器 eax 中取出一些东西并将其放入 esi。所以sum_a_b的返回值存储在eax中。

现在,如果我加快优化,整个 mul_c_d 调用将被 mov eax, 117044 替换。所以编译器不仅能够内联所有函数调用,它还能够在编译时预先计算结果。所以我们可以看出,我们启用的优化越多,知道结果存储在哪里就变得越来越不相关。

我在哪里可以阅读到这方面的信息?

所有的汇编程序都有点相似,因此通过学习任何汇编程序的基础知识,您可以大致了解它们的工作原理。当您学习汇编程序时,您将了解函数调用约定是如何“在底层”工作的。一些资源可以在这里找到:https://stackoverflow.com/tags/assembly/info

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-22
    • 1970-01-01
    • 1970-01-01
    • 2012-04-18
    • 2016-05-06
    • 1970-01-01
    • 2020-06-13
    相关资源
    最近更新 更多