内联函数及其实现

时间:2013-12-31 04:05:35

标签: c compilation inline

对于那些回答的人来说,这应该很容易。这个问题有一个合乎逻辑的答案,但我想要问一下验证。

我对程序流程如何工作的理解很简单。函数及其相关指令位于存储器中的某个点。内存中的此位置是用于存储此类指令的单个位置。调用时,该函数的第一条指令的位置存储在程序流程中。该内存指针指示CPU在内存中的位置查找所需功能的指令。跳转到该位置并执行指令后,恢复正常的程序流程并且CPU跳回原始地址指令所在的位置以继续执行连续指令。

据我了解,内联函数会直接粘贴到调用它们的位置。因此,当写入源文件并定义内联函数时,实际上在内存中存在多个位置,此函数的指令集位于该位置(即它的确切位置)。那么,也就是说内存中的source位置与非内联函数的位置相似?

此外,在编译过程中,编译器是否只是将内联函数准确地粘贴到调用的位置,并使用传递给它的参数删除/替换函数定义的任意参数名称?

5 个答案:

答案 0 :(得分:4)

  

我的理解是inline函数被粘贴到调用它们的位置。

这取决于。即使函数是inline,它也可能实际上没有被编译器内联。

  

那么,那就是说内存中没有类似于非内联函数的源位置?

这取决于函数的内联方式。如果在翻译单元中有4个对inline函数的调用,编译器可能会决定内联其中一个是正常的,其余调用应该使用常规函数调用。所以在这种情况下,有一个“源”位置和一个内联位置。

  

此外,在编译过程中,编译器是否只是将内联函数准确地粘贴到调用的位置,并使用传递给它的参数删除/替换函数定义的任意参数名称?

inline d函数必须与普通函数调用具有相同的含义。

答案 1 :(得分:3)

这几乎就像你在想的那样。 首先 - 它取决于语言/编译器。在C和GCC或MSVCC中,如果你告诉该函数是" inline"功能它并不意味着它将被内联!这取决于编译器及其实现,你的内联关键字/ pragma只是一个提示。

如果函数被标记为" inline"而不是粘贴在原始呼叫的所有地方但是......如果你正在编译一个库(静态或动态),它不会被删除。但是如果编译器决定内联它,它实际上粘贴了代码,并优化了调用。

顺便说一下。在Haskell(GHC)" inline" pragma不仅是一个提示,但你可以肯定,编译器将执行内联过程。就个人而言,我希望有一个C ++编译器,它将真正内联我告诉他的每个函数:)

答案 2 :(得分:2)

我的理解与你的理解相符。内联编译将删除该函数,并将其替换为该函数中的命令。任何参数都与传递给它们的值内联替换。正如你所说 - 没有跳转执行,没有函数添加到调用堆栈。

答案 3 :(得分:2)

编译器可以自由选择内联声明的函数是否应该是内联的。在内衬时,会有诸如此类的好处,

  • 执行速度很快。 (因为没有将刷新CUP缓存的跳转指令)
  • 内存使用情况
    • 代码存储器:如果你在许多地方使用的函数内嵌,那么代码大小将会增加。
    • 堆栈使用:如果内联函数使用更多变量,则使用更多堆栈空间。

修改 何时使用内嵌

  1. 使用内联函数代替#define。 (宏扩展是在每个处理时间内完成的。编译器完全不在图片中。但是对于内联函数,编译器在图片中,它可以进行错误检查......)
  2. 如果功能非常小,请使用内联函数。
  3. 如果该功能经常在很多地方使用,请使用内联功能。

答案 4 :(得分:1)

来自open-std.org的ISO/IEC 9899:TC2第112页告诉我们:

  

使用inline函数说明符声明的函数是内联函数   功能......制作功能   内联函数建议对函数的调用速度最快   (118)这些建议有效的程度如下   的实现定义(119)

该部分的脚注告诉我们:

  

(118)通过使用,例如,通常的函数调用的替代   机制,例如''内联替换''。 内联替换不是   文本替换,也不会创建新功能。因此,   例如,在体内使用的宏的扩展   函数使用函数体所具有的定义   出现,而不是调用函数的位置;和标识符   在身体发生的范围内的声明。 同样,   无论内联数量多少,函数都有一个地址   除外部定义外发生的定义。

     

(119)例如,实现可能永远不会内联执行   替换,或者可能只对调用进行内联替换   内联声明的范围。

我为我认为的部分添加了粗体字,或者纠正了对inline的理解。

如果您想强制或希望inline的特定行为,我建议您咨询您的编译器实现说明。关于(非)文本替换和单一地址的小问题很有意思。