在编译时或运行时更换内联代码?

时间:2016-05-12 11:00:51

标签: c++ c

我已经研究过,在编译时链接发生并且在运行时执行。在每个函数的内联函数中,调用代码由内联函数定义替换,但函数调用在运行时完成。但是当我审阅一些书籍时,在编译时替换了代码。谁能告诉我在编译时或运行时完成内联代码替换?

2 个答案:

答案 0 :(得分:5)

  

在编译时链接发生并在运行时执行

不完全。

build 时间,会发生三个阶段:

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

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

  2. 编译器解析翻译单元并发出目标代码。

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

  3. 链接器将编译的目标文件链接到可执行文件中。

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

    一些编译器现在提供链接时优化,这使得这张图片略显模糊。除此之外,具有非内联定义的函数可能会在构建周期的后期内联。

  4. 在任何一种情况下,函数内联都是在构建时执行的;此决定和生成的代码都内置在可执行文件中。

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

    • 编译器没有内联调用,这意味着有一个实际的调用指令。控制转移到该功能,它被执行,当它返回控制时,回传给通话后的指令

    • 编译器内联调用,并且函数代码的主体存在,执行只是继续进入(并通过)它。

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

    请注意,此编译模型并不普遍。例如,在Java中,"目标代码"是虚拟机的字节码,而不是本机机器码。这通常是在运行时编译的,这意味着内联和其他优化也可以在运行时进行。

答案 1 :(得分:0)

您可以将内联代码视为在编译时进行的文本替换。它有点复杂,因为这正是类似函数的宏所做的,但它们在概念上是相似的。

例如,请执行以下操作:

#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;
}

不是像没有内联那样调用max,而是在编译成代码时将其替换为代码

int main()
{
    cout << (5 > 9 ? 5 : 9) << endl;
    return 0;
}

所以它仍在解决(大于9?等等),最终会打印9,但不必调用该函数。

编辑: 它与宏不同的原因是安全性和期望相关。想象一下我们有

#define MAX(a,b) ((a)>(b) ? (a) : (b))

作为一个宏。如果要使用

int a=5;
int b=9;

cout << MAX(a++, b++) << endl;   // "10"
cout << a << ' ' << b << endl;   // "6 11"

我们希望ab分别打印6和10。但是,在宏中,这被替换为

((a++)>(b++) ? (a++) : (b++))

调用此功能后,我们会将(a++)>(b++)部分的后增量设为a=6b=10。然后我们跟进if语句,然后运行(b++)(其他条件),然后提供b=11,比预期多一个。

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

int a=5;
int b=9;

cout << max(a++, b++) << endl;   // Inline: "9"
cout << a << ' ' << b << endl;   // "6 10"