函数如何以及在何处保存一个函数的返回值'在调用其体内的其他函数之前?

时间:2015-08-22 13:01:23

标签: c function

我写了这段代码:

#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;

}

main() printf()函数内,调用 valFunc(a)后返回值为5,其中在调用 valFunc(b)

之前,main函数是否保存此值5

我知道如果这个函数写得如下,那么它会保存函数 valFunc(5) valFunc(7)的返回值。变量分别为 a b 。 :

#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;
}

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

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

2 个答案:

答案 0 :(得分:3)

它非常依赖于系统体系结构,但在最常见的情况下,当在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
....

我希望这澄清了这一点。

答案 1 :(得分:2)

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

更复杂的表达式的中间值存储在某个地方。在寄存器中,在内存位置,在堆栈上......由编译器决定。是的,您可以将它们视为临时变量......但实际上,它们并不是您的关注点。

  

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

由编译器决定。它可以检查你是在进行简单的操作,直接在编译时计算最终结果,即12,然后发出一个直接用12调用printf的代码。

这是as-if规则。只要您的应用程序具有相同的可观察方式(在本例中为print 12),编译器就可以执行任何操作。