1

假设我有一个任意函数:

void someFunc(int, double, char); 

我打电话给someFunc(8, 2.4, 'a');,实际发生了什么?8、2.4 和 'a' 如何获取内存、移入该内存并传递给函数?对于这样的情况,编译器有哪些类型的优化?如果我混合和匹配参数,例如someFunc(myIntVar, 2.4, someChar);

如果函数声明为 会发生什么inline

4

2 回答 2

4

值是否是文字没有区别(除非函数是内联的,然后编译器可以优化一些东西)。

通常,参数被放入寄存器或函数参数堆栈。无论它们是显式值还是变量。

如果没有优化,参数将被推入参数堆栈。在第一种情况下,首先取值x并放入寄存器eax,然后压入参数堆栈。foo打印x

    foo(x);
00361A75  mov         eax,dword ptr [x] 
00361A78  push        eax  
00361A79  call        get_4 (3612B7h) 
00361A7E  add         esp,4 
    foo(3);
00361A81  push        3    
00361A83  call        get_4 (3612B7h) 
00361A88  add         esp,4 

通过优化,编译器(在我的示例中)可以看到该函数,并且完全跳过了调用:

    foo(x);
01011000  mov         ecx,dword ptr [__imp_std::cout (101203Ch)] 
01011006  push        3    
01011008  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (1012038h)] 
    foo(3);
0101100E  mov         ecx,dword ptr [__imp_std::cout (101203Ch)] 
01011014  push        3    
01011016  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (1012038h)] 

foo定义为:

void foo(int x)
{
   std::cout << x;
}
于 2012-06-11T22:31:28.503 回答
1

通常C++ 函数在堆栈上工作。我将描述C 调用约定,因为它无需优化即可工作:

它将放在'a'堆栈的顶部。然后放到2.4栈顶,再放到8栈顶,然后为返回类型[1]添加空间,然后是调用函数中当前指令的指令指针,然后跳转到开头被调用函数的代码。
被调用的函数会查看栈,抓取参数,做它的事情,把结果放到栈上提供的空间,最后跳转到栈上指向的指令(大概就是那个函数的下一条指令)叫它)。现在处理器再次执行调用函数,然后它将结果复制到任何它想要的位置,并将所有其他内容从堆栈中弹出。*

还有其他调用约定(其中许多将参数保存在寄存器中)以节省时间,当然,由于异常,还有其他复杂性。根据调用函数的不同,它可能会内联调用,它会跳过列出的所有步骤,直接使用这些常量执行被调用的函数,或者在非常高级的编译器中,在某些条件下,它可能会创建函数的副本将这些参数硬编码,并调用该版本而不是无参数。

正如我所说,这是我多年前学到的所有理论。 Luchian Grigore 的答案有很多简洁的细节。

[1] Wikipedia 告诉我,如果结果是 single int,它会在寄存器而不是堆栈中返回。

于 2012-06-11T22:37:31.580 回答