让我们举个例子:
Class TestClass {
public:
int functionInline();
int functionComplex();
};
inline int TestClas::functionInline()
{
// a single instruction
return functionComplex();
}
int TestClas::functionComplex()
{
/* many complex
instructions
*/
}
void myFunc()
{
TestClass testVar;
testVar.functionInline();
}
假设所有的coment实际上都是单行或多行复杂代码的代码行。等效代码为(编译后):
void myFunc()
{
TestClass testVar;
// a single instruction
return functionComplex();
}
或者是:
void myFunc()
{
TestClass testVar;
// a single instruction
/* many complex
instructions
*/
}
换句话说,如果在内联函数内部调用一个普通函数,它是否会内联插入?
如果编译器可以看到函数在其他地方没有被调用(例如,在自由函数的情况下,它是static
),那么至少gcc已经内联了它很长一段时间。
当然,这也假设编译器实际上可以"看到"函数的源代码——只有当你使用"整个程序优化"(至少在MS和GCC编译器中可用)时,它才能内联不在源文件或源中包含的头文件中的函数。
显然,内联一个"大"函数没有什么好处(因为进行调用的开销在整个运行时中只占很小的一部分),如果该函数被多次调用(或者由于不是static
而"可能被多次调用"),编译器几乎肯定不会内联一个"大"函数。
总之:也许大型函数是内联的,但很可能不是。
请检查我为VC++2010和g++生成的汇编代码。在本例中,两个编译器实际上都没有将任何函数视为内联函数。
代码:
class TestClass {
public:
int functionInline();
int functionComplex();
};
inline int TestClass::functionInline()
{
// a single instruction
return functionComplex();
}
int TestClass::functionComplex()
{
/* many complex
instructions
*/
return 0;
}
int main(){
TestClass t;
t.functionInline();
return 0;
}
VC++2010:
int main(){
01372E50 push ebp
01372E51 mov ebp,esp
01372E53 sub esp,0CCh
01372E59 push ebx
01372E5A push esi
01372E5B push edi
01372E5C lea edi,[ebp-0CCh]
01372E62 mov ecx,33h
01372E67 mov eax,0CCCCCCCCh
01372E6C rep stos dword ptr es:[edi]
TestClass t;
t.functionInline();
01372E6E lea ecx,[t]
01372E71 call TestClass::functionInline (1371677h)
return 0;
01372E76 xor eax,eax
}
Linux G++:
main:
.LFB3:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
subq $16, %rsp
leaq -1(%rbp), %rax
movq %rax, %rdi
call _ZN9TestClass14functionInlineEv
movl $0, %eax
leave
ret
.cfi_endproc
两条线路
01372E71调用TestClass::functionInline(1371677h)
和
调用_ZN9TestClass14函数InlineEv
指示函数functionInline不是内联的。
现在看看函数内联汇编:
inline int TestClass::functionInline()
{
01372E00 push ebp
01372E01 mov ebp,esp
01372E03 sub esp,0CCh
01372E09 push ebx
01372E0A push esi
01372E0B push edi
01372E0C push ecx
01372E0D lea edi,[ebp-0CCh]
01372E13 mov ecx,33h
01372E18 mov eax,0CCCCCCCCh
01372E1D rep stos dword ptr es:[edi]
01372E1F pop ecx
01372E20 mov dword ptr [ebp-8],ecx
// a single instruction
return functionComplex();
01372E23 mov ecx,dword ptr [this]
01372E26 call TestClass::functionComplex (1371627h)
}
因此,函数Complex也不是内联的。
否,如果您希望以内联方式插入复杂函数,则还必须指定inline
关键字
在实践中,使用__forceinline
关键字(在windows上,__always_inline
在linux上),否则如果有很多指令,编译器将忽略该关键字。
首先,内联函数只是编译器的一个指令。不能保证编译器会执行内联。
其次,当您指定一个函数为内联时,它会告诉编译器两件事
1) 函数可能是内联的候选者。不能保证它是否会被内联2) 此功能具有内部链接。也就是说,函数只有在编译的翻译单元中才可见。无论函数是否实际内联,都可以保证这种内部链接。
在您的情况下,functionInline被指定为inline,但functionComplex不是。functionComplex具有外部链接。编译器永远不会对具有外部链接的函数进行内联。
因此,您的问题的简单答案是"否"。一个正常的(没有内联关键字并在类外定义的函数)函数永远不会内联