Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 内联代码是在编译时还是在运行时被替换?_C++_C - Fatal编程技术网

C++ 内联代码是在编译时还是在运行时被替换?

C++ 内联代码是在编译时还是在运行时被替换?,c++,c,C++,C,我已经研究过,在编译时链接发生,在运行时执行发生。每次函数调用时,内联函数中的代码被内联函数定义替换,但函数调用在运行时完成。但当我参考一些书时,代码的替换是在编译时完成的。有人能告诉我内联代码替换是在编译时还是运行时完成的吗 您可以将内联代码看作是在编译时进行的文本替换。它比这个稍微复杂一点,因为这正是像宏这样的函数所做的,但它们在思想上是相似的 例如,以以下内容为例: #include <iostream> using namespace std; inline int max

我已经研究过,在编译时链接发生,在运行时执行发生。每次函数调用时,内联函数中的代码被内联函数定义替换,但函数调用在运行时完成。但当我参考一些书时,代码的替换是在编译时完成的。有人能告诉我内联代码替换是在编译时还是运行时完成的吗

您可以将内联代码看作是在编译时进行的文本替换。它比这个稍微复杂一点,因为这正是像宏这样的函数所做的,但它们在思想上是相似的

例如,以以下内容为例:

#include <iostream>
using namespace std;

inline int max(int a, int b)
{
    return a > b ? a : b;
}

int main()
{
    cout << max(5,9) << endl;   // "9"
    return 0;
}
作为一个宏。如果我们使用

int a=5;
int b=9;

cout << MAX(a++, b++) << endl;   // "10"
cout << a << ' ' << b << endl;   // "6 11"
调用此函数时,我们将在
(a++)>(b++)
部分增加post增量,这将给出
a=6
b=10
。然后,我们继续使用if语句,并运行
(b++)
(else条件),它将给出
b=11
,比预期的多出一个

使用inline,我们获得了预期的结果,因为它将在语句运行后执行这些post增量

int a=5;
int b=9;

cout << max(a++, b++) << endl;   // Inline: "9"
cout << a << ' ' << b << endl;   // "6 10"
inta=5;
int b=9;
库特
在编译时进行链接,在运行时执行

不完全是

在构建时,会发生三个阶段:

  • 预处理器通过文本替换准备每个翻译单元(宏调用被宏定义的文本替换,
    #include
    被包含文件的内容替换,等等)

    没有进行任何非文本处理(它不理解任何程序结构或含义)

  • 编译器解析翻译单元并发出目标代码

    这包括代码生成之前、期间和之后的优化。函数内联传统上是这些优化之一,因为它发生在生成调用站点代码时

  • 链接器将编译的对象文件链接到可执行文件中

    原则上,链接根本不会改变目标代码,除了符号表和偏移

    一些编译器现在确实提供了链接时间优化,这使这张图有点模糊。除其他外,具有非内联定义的函数可能在构建周期的后期内联

  • 无论哪种情况,函数内联都是在构建时执行的;此决策和生成的代码都内置到可执行文件中

    在运行时,当调用实际执行时,会发生以下两种情况之一:

    • 编译器没有内联调用,这意味着存在实际的调用指令。控制权转移到函数,函数被执行,当它返回时,控制权传回调用后的指令

    • 编译器内联了调用,函数代码的主体出现了,执行只是继续(并通过)它

    在第二种情况下,您不会考虑内联发生在运行时-它仍然发生在编译时,当代码生成时。



    请注意,此编译模型不是通用的。例如,在Java中,“对象代码”是虚拟机的字节码,而不是本机代码。这通常是在运行时编译的,这意味着内联和其他优化也可以在运行时进行。

    从技术上讲,内联代码替换(如果有)应该在编译时进行,因为:

    • 完全可以在编译时完成
    • 如果它发生在运行时,新生成的代码部分必须再次编译以使其可执行,这毫无意义
    还要注意的是,不能保证您会得到类似“内联替换”的东西。根据N1570,6.7.4第6段:

    使用内联函数说明符声明的函数是内联函数 功能。使函数成为内联函数意味着调用 该功能应尽可能快此类事件发生的程度 建议的有效性取决于实施情况。

    如您所见,唯一的保证是函数调用“尽可能快”,这并不是很有用。第139条脚注进一步指出:

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

    编译时。
    编译器实际上可以忽略内联关键字。它只是一个提示(除非内联是必要的,以便允许在头文件中定义函数,而不会由于函数在多个翻译单元中定义而生成错误消息)。

    类似函数的宏是文本替换。使用此内联函数,
    max(a++,b++)
    将只计算
    a++
    b++
    一次,而如果使用文本替换,则其中任何一个都将计算两次。因此,内联函数被认为比宏之类的函数更安全。它类似于宏,但更安全。请解释一下我的答案中哪一部分值得否决票?带有宏
    cout-Oops的代码,谢谢!我认为您遗漏了一个关键细节:内联函数意味着没有函数调用要执行。可能重复“链接器不可能更改此项,因为它必须重新编写可执行代码,这不是它的工作。”现在很多编译器都会选择链接时代码生成,其中目标文件包含代码的表示,但最终代码只会在链接时生成,以便在代码“链接”时执行此类优化。是的,起初我忽略了LTO,因为我担心OP不理解编译时和运行时之间的区别。
    
    int a=5;
    int b=9;
    
    cout << MAX(a++, b++) << endl;   // "10"
    cout << a << ' ' << b << endl;   // "6 11"
    
    ((a++)>(b++) ? (a++) : (b++))
    
    int a=5;
    int b=9;
    
    cout << max(a++, b++) << endl;   // Inline: "9"
    cout << a << ' ' << b << endl;   // "6 10"