如果你有带有常量的函数调用,它没有副作用,并且不依赖于任何东西,如下所示:
int foo(int a,int b) { 返回a+b; }
函数是否内联?或者,也许函数是在编译时求值的,并插入求值结果来代替函数调用?
我尝试使用相当旧的 gcc 来编译它 -
#include <iostream>
int foo(int a,int b)
{
return a+b;
}
int main()
{
std::cout << foo(100, 123) ;
}
主要编译到此-
LFB1439:
subq $8, %rsp
.LCFI1:
movl $223, %esi
movl $_ZSt4cout, %edi
call _ZNSolsEi
xorl %eax, %eax
addq $8, %rsp
ret
因此它在编译时编译了加法,得到 223。
显然,结果取决于您的代码和编译器,但这表明它可以并且可以在编译时内联和计算加法(如果可以的话)。
C++ 中没有。它们不会像那样在编译时执行 - 除非编译器神奇地执行它。但是,这不能强迫。
但是,对于 C++11,您可以使用
constexpr
来确保它在编译时进行评估,例如:
constexpr int get_five() {return 5;}
因此,您可以将函数重写为:
constexpr int foo(int a,int b)
{
return a+b;
}
请注意,如果该函数的参数并不总是恒定,您不必担心。
来自维基百科:
如果使用 constexpr 函数或构造函数调用以下参数 不是常量表达式,调用的行为就像函数是 不是 constexpr,并且结果值不是常量表达式。 同样,如果 constexpr 的 return 语句中的表达式 函数不会计算为特定的常量表达式 调用,结果不是常量表达式。
这意味着
foo(1,1)
将是恒定的,但是:
int i,j;
cin >> i >> j;
foo(i,j) // this is not constant
参考:http://en.wikipedia.org/wiki/C%2B%2B11#constexpr_-_Generalized_constant_expressions
如果您在头文件中定义它,那么它很有可能被内联。如果您使用整型编译时常量作为其参数,那么编译器应该能够在编译时执行该函数。
即使没有这样的保证,您也应该相信您的编译器。他们非常擅长优化你的代码。如果要确保函数在编译时执行,可以添加
constexpr
重载(仅限 C++11):
constexpr int foo(int a,int b){
return a+b;
}
我尝试过以下片段:
int add(int a, int b) {
return a + b;
}
int main() {
return add(5, 2);
}
当使用 GCC 和 -O3 标志编译时,它会被编译为:
0x08048300 <+0>: mov $0x7,%eax
0x08048305 <+5>: ret
因此,你可以看到它实际上是在编译时执行的。
是否执行此类优化不是 C 和 C++ 语言的定义部分。本质上,只要生成的代码根据源代码有效,编译器就可以自由地进行它认为合适的优化。在一般情况下,在更高的优化级别,此调用可以是内联的,或者如果调用站点始终传入常量(编译时已知的值),则可以在编译时计算结果,并且完全避免任何运行时开销。
优化编译器选择不内联函数的一般情况是:
还有一个需要注意的问题是内联会改变函数的链接。
使用
-O3
在 GCC 和 G++ 上编译以下 C 代码:
int foo(int a, int b) {
return a+b;
}
int main(void)
{
return foo(1, 2);
}
产生以下汇编代码:
00000000004004e0 <main>:
main():
4004e0: b8 03 00 00 00 mov $0x3,%eax
4004e5: c3 retq
您可以检查程序集列表以查看它是否被内联,但如前所述,它是特定于编译器的。
这取决于编译器和优化设置,但一般来说,您可以假设当您打开至少一点优化时,任何足够高级的编译器都会内联这样一个简单的函数。
当你想确保函数是内联的时,你总是可以使用 inline 关键字来声明它:
inline int foo(int a,int b){
return a+b;
}
但通常应该避免这种善意的提示,因为大多数编译器比大多数程序员更擅长决定内联哪些函数。
如何在编译时计算该函数的可能场景:
1) 在内联优化阶段之一期间编译器内联
foo
函数。注意:在看到程序的汇编代码之前,您永远不会确切地知道该函数是否是内联的。即使您使用
inline
说明符。编译器可能会忽略此说明符或没有此说明符的内联函数。