声明内联关键字的区别

时间:2013-04-02 14:31:51

标签: c

inline void foo();

int main() {
    foo(); return 0;
}

void foo(){
}

foo的声明设为inline而非foo的定义是否有任何区别?对面怎么样?如何将它们标记为inline

1 个答案:

答案 0 :(得分:4)

这是C11关于内联的所有内容(注意:inline是函数说明符,目前唯一的其他函数说明符是_Noreturn)(强调我的):

  

6.7.4

     

2。函数说明符只能用于声明函数的标识符。

     

3。具有外部链接的函数的内联定义不应包含a的定义   具有静态或线程存储持续时间的可修改对象,且不得包含引用   到具有内部联系的标识符。

     

5。函数说明符可能出现多次;行为和它一样    只出现过一次。

     

6。使用内联函数说明符声明的函数是内联函数。制作一个    函数内联函数表明对函数的调用应尽可能快。 138    这些建议有效的程度是实施定义的。 139

     

7。具有内部链接的任何函数都可以是内联函数。用于外部功能   链接,以下限制适用:如果使用内联声明函数   函数说明符,那么它也应该在同一个翻译单元中定义。 如果全部的话   翻译单元中函数的文件范围声明包括内联函数   没有extern的说明符,那么该翻译单元中的定义是内联的   定义。 内联定义不提供函数的外部定义,   并且不禁止在另一个翻译单元中使用外部定义。内联定义   提供了外部定义的替代方案,翻译人员可以使用该定义来实现   在同一翻译单元中对该功能的任何调用。没有具体说明是否打电话给   函数使用内联定义或外部定义。

     

10。示例1使用外部链接声明内联函数可能会导致外部链接   定义或仅可在翻译单元内使用的定义。带有的文件范围声明   extern创建一个外部定义。以下示例显示了整个翻译单元。

inline double fahr(double t)
{
    return (9.0 * t) / 5.0 + 32.0;
}
inline double cels(double t)
{
    return (5.0 * (t - 32.0)) / 9.0;
}
extern double fahr(double); // creates an external definition
double convert(int is_fahr, double temp)
{
    /* A translator may perform inline substitutions */
    return is_fahr ? cels(temp) : fahr(temp);
}
     

11。请注意,fahr的定义是外部定义,因为fahr也是使用extern声明的,但是    cels的定义是内联定义。因为cels具有外部链接并被引用,所以    外部定义必须出现在另一个翻译单元中(见6.9);内联定义和外部定义    定义是不同的,可以用于呼叫。

     

138 例如,使用通常的函数调用机制的替代方法,例如''inline   代换''。内联替换不是文本替换,也不是创建新函数。   因此,例如,函数体内使用的宏的扩展使用了   它在函数体出现时的定义,而不是调用函数的位置;和   标识符指的是正文出现的范围内的声明。同样,该功能有一个   单个地址,不管外部发生的内联定义的数量   定义

     

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

     

6.9

     

5。外部定义是外部声明,也是函数的定义    (内联定义除外)或对象。

     

J.1未指明的行为

     

- 对内联函数的调用是使用内联定义还是外部定义   功能(6.7.4)。

     

J.2未定义的行为

     

- 使用内联函数说明符声明具有外部链接的函数,但是   也没有在同一翻译单元(6.7.4)中定义。

     

J.3实现 - 定义行为

     

J.3.8提示

     

- 使用内联函数说明符进行建议的程度   有效(6.7.4)。


这对人类意味着什么

  • 6.7.4.3:如果链接器也可以看到内联函数,则它不能有static个局部变量。 它也不能使用文件范围变量/函数(定义为全局标识符,但使用static)。 (注意:可以有人 告诉我对这最后一句话的理解是否正确?这感觉不对。)

  • 6.7.4.6:使函数内联不会强制编译器像一个宏一样行动。它只是提示编译器 你希望功能快。

  • 6.7.4.7

    1. 如果您使用static功能,则可以将其设为inline
    2. 如果在翻译单元(TU)(例如,预处理的源文件)中,编译器会看到inline函数声明, 在同一个TU的某个地方,它应该能够找到它的定义。
    3. 如果您在任何地方声明了一个放置inline的函数,那么编译器会将该函数看作static(但不完全正确)。
    4. 如果在TU中使用如第3点中的函数,则该函数将获得外部链接,因此将获得另一个实现 它应该存在于其他一些TU中。编译器的选择是使用函数的内联版本或 外部的。 1
  • 138 :无论您在不同的TU中定义内联函数多少次,它们都有"相同的"地址。我相信 这也意味着如果你使用函数指针来存储地址,然后通过那个指针调用函数,那么 将调用函数的外部定义。

  • 6.9.5:正常的函数定义既声明又定义了外部函数。但正如我们在内联定义之前看到的那样 该函数没有定义一个外部可见的定义,即使它可以声明一个外部函数。

1 在您的示例中,如果您在inline的定义中放置foo,则gcc会收到错误(在链接阶段) foo有未定义的引用。如果将foo的另一个实现放在同一个文件中,则会出现重新定义错误。 这与我所说的一致:全内联声明/定义不提供外部链接,如果使用该功能 在TU中,它需要在另一个TU中定义。


进一步阅读: