【问题标题】:How and where does a function save the 'returned value of one function' before calling other functions inside its body?一个函数在调用其体内的其他函数之前如何以及在哪里保存“一个函数的返回值”?
【发布时间】:2015-11-16 08:24:17
【问题描述】:

我写了这段代码:

#include<stdio.h>
int valFunc(int val){
     return val;
}


int main(){
     int a  = 5;
     int b = 7;

     printf("%d",valFunc(a)+valFunc(b));

     return 0;

}

ma​​in()printf()函数内部,调用valFunc(a)后返回值为5,其中主函数在调用 valFunc(b) 之前会保存这个值 5 吗?

我知道如果这个函数像下面这样写,那么它会将函数 valFunc(5)valFunc(7) 的返回值保存为整数变量分别为 ab。 :

#include<stdio.h>
int valFunc(int val){
     return val;
}


int main(){


  int a = valFunc(5);
  int b = valFunc(7);

  printf("%d",a+b);


  return 0;
}

但是在以前的代码中,我无法理解函数将返回值保存在哪里?它是否创建隐式变量并在调用其他函数之前使用它们来保存进度,或者是否有其他机制?请解释一下。

在调用其他函数之前,它是否会创建任何临时变量来将这些值存储在 运行时堆栈 中?在我在问题中编写的第二个代码中,很明显 ma​​in() 会将这些值存储在 ab 中并将它们放入在运行时堆栈上。但是 ma​​in() 将如何为第一个代码执行此操作,因为没有变量?

【问题讨论】:

  • 这更像是 C++ 临时对象,请参见:stackoverflow.com/questions/9109831/…
  • 请指定 C 和 C++ 中的一种,因为这两种语言对于在这种情况下发生的事情有不同的概念。我将您的问题重新标记为 C,因为您的所有代码看起来都像 C 代码。

标签: c function


【解决方案1】:

它非常依赖于系统架构,但在最常见的情况下,当在 C 中调用函数时,结果会在特定寄存器中返回,总是相同的。 如果我们关注 Intel X32-64,则返回值通过寄存器 eax 传递 32 位,rax 传递 64 位。在这种情况下,编译器发出的代码用于 IA32将(或多或少):

lea eax, a                  //Get parameter address
mov eax, dword ptr [eax]    //Get the value
push eax                    //pass parameter on stack
call valFunc                //call function
mov ebx, eax                //save result in register ebx
lea eax, ba                 //Get parameter address
mov eax, dword ptr [eax]    //Get the value
push eax                    //pass parameter on stack
call valFunc                //call function
add  eax, ebx               //sum the results
push eax                    //pass the sum as parameter on stack
lea eax, fmtstr             //Get the address of the format string "%d"
push eax                    //push it onto the stack
call _printf

作为一种变体,结果可以保存在堆栈中(即在所有寄存器都在使用的情况下):

....
call valFunc                //call function
push eax                    //save result on the stack
lea eax, ba                 //Get parameter address
mov eax, dword ptr [eax]    //Get the value
push ebx                    //save ebx on the stack
mov ebx, eax                //save result in register ebx
call valFunc                //call function
add  eax, ebx               //sum the results
pop  ebx                    //Restore register ebx from stack
push eax                    //pass the sum as parameter on stack
....

我希望这能澄清这一点。

【讨论】:

    【解决方案2】:

    有趣的是,您并不担心a+b。但这是一个非常相似的事情。

    更复杂的表达式的中间值存储在……某处。在寄存器中,在内存位置,在堆栈中......这取决于编译器。是的,您可以将它们视为临时变量……但实际上,它们与您无关。

    在我在问题中编写的第二个代码中,很明显 main() 会将这些值存储在 a 和 b 中,并将它们放在运行时 堆栈

    这取决于编译器。它可以检查你是否在做简单的操作,在编译时直接计算最终结果,即 12,然后发出代码直接调用 printf 与 12。

    这是假设规则。只要您的应用程序以相同的可观察方式运行(在本例中,打印 12),编译器就可以为所欲为。

    【讨论】:

    • 我已经在问题中添加了更多信息...请也基于此回答。
    • @ThunderWiring:为什么不呢?如果编译器知道它不会被触及,那它是完全安全的。
    • 如果您使用不同的编译器怎么办?行为如何变化?
    • 如果您要更改编译器选项和优化级别怎么办?如果有不同的调用约定怎么办?没有通用的答案。检查发出的代码...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 2022-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    相关资源
    最近更新 更多