【问题标题】:Inline function prototype vs regular declaration vs prototype内联函数原型 vs 常规声明 vs 原型
【发布时间】:2011-12-16 20:45:42
【问题描述】:

内联函数和main函数有什么区别:

inline double cube(double side)
{
   return side * side * side;
}

int main( )
{
    cube(5);
}

vs 只是定期声明一个函数,例如:

double cube(double side)
{
   return side * side * side;
}

int main( )
{
    cube(5);
}

vs 函数原型?

double cube(double);

int main( )
{
    cube(5);
}

double cube(double side)
{
   return side * side * side;
}

【问题讨论】:

标签: c++ function-prototypes function-declaration inline-functions


【解决方案1】:

inline 函数可以在多个翻译单元(cpp 文件 + 包含)中定义,并且是对编译器内联函数的提示。它通常放置在增加编译时间的标头中,但可以导致更快的代码。它还允许在许多编译单元中使用该函数。

//cube.h
inline double cube(double side)
{
   return side * side * side;
}

//cube.cpp
int main( )
{
    cube(5);
}

定期定义它是正常的方法,它(通常)在 cpp 文件中定义并链接。它不容易从其他编译单元中使用。

//cube.cpp
double cube(double side)
{
   return side * side * side;
}

int main( )
{
    cube(5);
}

原型允许您告诉编译器一个函数将在链接时存在,即使它还不存在。这允许 main 调用该函数,即使它还不存在。通常,原型位于头文件中,因此其他编译单元可以调用该函数,而无需自己定义它。这具有最快的编译时间,并且该函数很容易在其他编译单元中使用。

//cube.h
double cube(double);

//cube.cpp
int main( )
{
    cube(5);
}

double cube(double side)
{
   return side * side * side;
}

【讨论】:

  • ...可以在单个编译单元(cpp 文件 + 包含)中多次定义 - 您的意思是 不同的 个编译单元吗?
  • 不,inline 被允许违反 ODR,例如模板。否则,很难在头文件中放入内联,如果它不在头文件中,愚蠢的编译器就无法内联它!
  • 出色且易于理解的解释,先生/女士。非常感谢!
  • @MooingDuck: anatolyg 是对的,inline 函数可以在一个翻译单元中只定义一次,即使它可以在一个程序中定义多次而不违反ODR。
  • 如果cube.h 包含在cube.cpp 和另一个翻译单元中,则最后一个示例是未定义的行为,不需要诊断。一个函数在一个单元中可能不是inline,在另一个单元中是非内联的。
【解决方案2】:

性能方面,它们都是一样的,因为inline 只是对编译器的提示。如果使用声明/定义的分离并且定义在不同的翻译单元上,那么编译器将更难内联它(但有些实现会这样做)。

与是否创建函数 inline 的区别在于,如果链接器不止一次地看到同​​一个函数的内联定义,它不会报错。

【讨论】:

    【解决方案3】:

    3 程序编译为与g++ -S -O3 $file.cc 完全相同。 除了第二个例子,double cube(double side) 的定义虽然在int main() 中内联,但仍然以非内联形式存在。

    _main:
    pushl   %ebp
    movl    $16, %eax
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    call    __alloca
    call    ___main
    leave
    xorl    %eax, %eax
    ret
    

    【讨论】:

    • 您指出的区别在于实现的细节,即使实际上是内联的,某些编译器也会始终生成所有函数,因为您可以获取inline函数的地址,并且如果稍后在同一个 TU 中请求该函数的地址,编译器在处理该函数时可能不知道。
    【解决方案4】:

    当您声明一个内联函数时,编译器会尝试通过或多或少地将函数体复制到调用它的位置来加速代码。这只是一个建议,由编译器决定是否可行。

    我不确定第三个示例会发生什么。我想这将取决于所使用的工具链。

    【讨论】:

    • 最后一个只是main()之前的一个函数原型。它们似乎都以相同的方式工作,但我似乎不明白有什么区别。
    猜你喜欢
    • 1970-01-01
    • 2011-08-07
    • 2012-07-15
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    相关资源
    最近更新 更多