我一直在创建一个简单的包装器类。我随机发现(或似乎是)内联函数仍编译为函数调用。我创建了一个示例类来测试事物,这就是我发现的东西:
请考虑以下课程:
//compile with MSVC
class InlineTestClass
{
public:
int InternalInt;
int GetInt() {return InternalInt;}
inline int GetInt_Inl() {return InternalInt;}
//__forceinline -Forces the compiler to implement the function as inline
__forceinline int GetInt_ForceInl() {return InternalInt;}
};
该课程有3个功能供参考。
实现如下:
InlineTestClass itc;
itc.InternalInt = 3;
int myInt;
myInt = itc.InternalInt; //No function
myInt = itc.GetInt(); //Normal function
myInt = itc.GetInt_Inl(); //Inline function
myInt = itc.GetInt_ForceInl(); //Forced inline function
myInt设置的结果汇编代码(来自反汇编程序):
451 myInt = itc.InternalInt;
0x7ff6fe0d4cae <+0x003e> mov eax,dword ptr [rsp+20h]
0x7ff6fe0d4cb2 <+0x0042> mov dword ptr [rsp+38h],eax
452 myInt = itc.GetInt();
0x7ff6fe0d4cb6 <+0x0046> lea rcx,[rsp+20h]
0x7ff6fe0d4cbb <+0x004b> call nD_Render!ILT+2125(?GetIntInlineTestClassQEAAHXZ) (00007ff6`fe0d1852)
0x7ff6fe0d4cc0 <+0x0050> mov dword ptr [rsp+38h],eax
453 myInt = itc.GetInt_Inl();
0x7ff6fe0d4cc4 <+0x0054> lea rcx,[rsp+20h]
0x7ff6fe0d4cc9 <+0x0059> call nD_Render!ILT+1885(?GetInt_InlInlineTestClassQEAAHXZ) (00007ff6`fe0d1762)
0x7ff6fe0d4cce <+0x005e> mov dword ptr [rsp+38h],eax
454 myInt = itc.GetInt_ForceInl();
0x7ff6fe0d4cd2 <+0x0062> lea rcx,[rsp+20h]
0x7ff6fe0d4cd7 <+0x0067> call nD_Render!ILT+715(?GetInt_ForceInlInlineTestClassQEAAHXZ) (00007ff6`fe0d12d0)
0x7ff6fe0d4cdc <+0x006c> mov dword ptr [rsp+38h],eax
如上所示,直接来自InlineTestClass的成员的(myInt)设置为(符合预期) 2条mov指令。 通过 GetInt 函数进行设置会导致调用(按预期),但是 GetInt_Inl 和 GetInt_ForceInl (内联函数)也会导致函数调用。
似乎内联函数已被编译为普通函数,而完全忽略了内联(如果我错了,请纠正我)。
根据MSVC documentation,这是奇怪的原因:
内联和__inline指示符指示编译器插入一个 将函数主体复制到调用函数的每个位置。
(我认为)会导致:
inline int GetInt_Inl() {return InternalInt; //Is the function body}
myInt = itc.GetInt_Inl(); //Call site
//Should result in
myInt = itc.InternalInt; //Identical to setting from the member directly
这意味着汇编代码也应直接与类成员的设置相同,但不是。
答案 0 :(得分:2)
默认情况下,类中定义的函数为“内联推荐”。因此,内联绝对没有任何作用。同样,无论如何,编译器始终可以否决程序员的关键字。只是建议而已。
摘自C ++ 17草案(第147页):
内联说明符向实现指示,在调用点处对函数体进行内联替换比通常的函数调用机制更可取。在调用点不需要执行此内联替换的实现;但是,即使省略了此内联替换,仍应遵守本节中指定的其他内联函数规则。
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf