内联扩展编译成函数调用[c++]
inline expansion compiles into a function call [c++]
简介:
我一直在创建一个简单的包装器 classes。我随机发现 (或者它看起来是) 一个内联函数仍然编译成一个函数调用。我创建了一个示例 class 来测试结果,这是我发现的:
考虑以下 class:
//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;}
};
这个class有3个函数可以参考
- GetInt函数是标准函数。
- GetInt_Inl函数是一个内联函数。
- GetInt_ForceInl 函数是确保内联函数
编译器决定不将 GetInt_Inl 实现为内联函数
像这样实现:
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 的 member 的设置(myInt)是 (如预期) 2 mov 指令长。
GetInt 函数的设置导致函数调用 (如预期),但是 GetInt_Inl 和 GetInt_ForceInl(内联函数)也会导致函数调用。
似乎内联函数已被编译为一个完全忽略内联的普通函数(如果我错了请纠正我).
根据 MSVC documentation,这是奇怪的原因:
The inline and __inline specifiers instruct the compiler to insert a
copy of the function body into each place the function is called.
哪个 (我认为) 会导致:
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
这意味着汇编代码也应该与 class 成员直接设置的代码相同,但事实并非如此。
问题:
- 我是不是遗漏了什么或者功能实现不正确?
- 我在解释内联关键字的功能吗?这是什么?
- 为什么这些内联函数会导致函数调用?
类 中定义的函数默认为 'recommended inline'。所以 inline 什么都不做。此外,无论如何,编译器总是可以自由地否决程序员的关键字。这只是建议。
来自 C++17 草案(第 147 页):
The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions specified in this subclause shall still be respected.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf
简介:
我一直在创建一个简单的包装器 classes。我随机发现 (或者它看起来是) 一个内联函数仍然编译成一个函数调用。我创建了一个示例 class 来测试结果,这是我发现的:
考虑以下 class:
//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;}
};
这个class有3个函数可以参考
- GetInt函数是标准函数。
- GetInt_Inl函数是一个内联函数。
- GetInt_ForceInl 函数是确保内联函数 编译器决定不将 GetInt_Inl 实现为内联函数
像这样实现:
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 的 member 的设置(myInt)是 (如预期) 2 mov 指令长。 GetInt 函数的设置导致函数调用 (如预期),但是 GetInt_Inl 和 GetInt_ForceInl(内联函数)也会导致函数调用。
似乎内联函数已被编译为一个完全忽略内联的普通函数(如果我错了请纠正我).
根据 MSVC documentation,这是奇怪的原因:
The inline and __inline specifiers instruct the compiler to insert a copy of the function body into each place the function is called.
哪个 (我认为) 会导致:
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
这意味着汇编代码也应该与 class 成员直接设置的代码相同,但事实并非如此。
问题:
- 我是不是遗漏了什么或者功能实现不正确?
- 我在解释内联关键字的功能吗?这是什么?
- 为什么这些内联函数会导致函数调用?
类 中定义的函数默认为 'recommended inline'。所以 inline 什么都不做。此外,无论如何,编译器总是可以自由地否决程序员的关键字。这只是建议。
来自 C++17 草案(第 147 页):
The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions specified in this subclause shall still be respected.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf