假设我有一个任意函数:
void someFunc(int, double, char);
我打电话给someFunc(8, 2.4, 'a');
,究竟发生了什么? 8,2.4和'a'如何获取内存,移入该内存,并传递给该函数?编译器对这些情况有什么类型的优化?如果我混合和匹配参数,例如someFunc(myIntVar, 2.4, someChar);
?
如果函数声明为inline
会怎样?
答案 0 :(得分: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;
}
答案 1 :(得分:1)
通常 C ++函数在堆栈上工作。我会在没有优化的情况下描述C calling convention:
它会将'a'
放在堆栈顶部。然后它将2.4
置于堆栈顶部,然后将8
置于堆栈顶部,然后为返回类型 [1] 添加空间,然后指令调用函数中当前指令的指针,然后跳转到被调用函数代码的开头
被调用的函数将查看堆栈,获取参数,执行它的操作,将结果放在堆栈上提供的空间中,最后跳转到堆栈上指向的指令(可能是下一条指令)调用它的函数)。既然处理器再次执行调用函数,它会将结果复制到任何需要的地方,并将所有其他内容从堆栈中弹出。*
有other calling conventions(其中许多将保留寄存器中的参数)以节省时间,当然,由于例外,还有其他并发症。根据调用函数,它可以内联调用,它会跳过列出的所有步骤,直接执行带有这些常量的被调用函数,或者在 very 高级编译器中执行,在某些情况下,它可能会创建具有硬编码参数的函数的副本,并将该版本称为无参数。
正如我所说,这是我多年前学到的理论。 Luchian Grigore's answer有很多简洁的细节。
[1]维基百科告诉我,如果结果是单个int
,则它会在寄存器而不是堆栈中返回。