内联扩展编译为函数调用 [C++]
inline expansion compiles into a function call [c++]
简介:
我一直在创建一个简单的包装类。我随机发现(或看起来是(一个内联函数仍然编译成函数调用。我创建了一个示例类来测试内容,这就是我发现的:
请考虑以下类:
//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 个函数供参考。
- 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成员的设置(myInt(是(如预期的那样(2 mov 指令长。从 GetInt函数进行设置会导致函数调用(如预期的那样(,但是GetInt_Inl和GetInt_ForceInl(内联函数(也会导致函数调用。
看起来好像内联函数已被编译为完全忽略内联的普通函数(如果我错了,请纠正我(。
根据 MSVC 文档,这是奇怪的原因:
内联和__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
这意味着汇编程序代码也应该与直接来自类成员的设置相同,但事实并非如此。
问题:
- 我是否遗漏了某些内容或功能实现不正确?
- 我是否在解释内联关键字的功能?这是什么?
- 为什么这些内联函数会导致函数调用?
默认情况下,类中定义的函数是"推荐内联的"。所以内联绝对没有做任何事情。此外,无论如何,编译器总是可以自由地否决程序员的关键字。这只是建议。
摘自C++17草案(第147页(:
内联说明符向实现指示,在调用点对函数体进行内联替换比通常的函数调用机制更可取。在调用点执行此内联替换不需要实现;但是,即使省略了此内联替换,仍应遵守本子条款中指定的内联函数的其他规则。
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf
相关文章:
- 函数调用中参数的顺序重要吗
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 变量没有改变?通过向量的函数调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 模板函数调用
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 析构函数调用
- 成员函数调用和C++对象模型
- 使用共享指针的函数调用,其对象应为 const
- C++:编译时检查匹配的函数调用对?
- 函数调用C++中的参数太少
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- 返回指向对象的指针的函数调用是否为 prvalue?
- C++ 如何重载 [] 运算符并进行函数调用
- 代码的效率. 转到和函数调用
- 是同一作用域的函数部分中的函数调用
- 如何封装一个函数,以便它只能由同一类中的一个其他函数调用?
- 类型擦除的std::function与虚拟函数调用的开销