3
inline void foo();

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

void foo(){
}

foo如果将' 声明设置为 'inline和 not foo' 定义有什么区别吗?相反的呢?将它们都标记为inline怎么样?

4

1 回答 1

4

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

6.7.4

2. 函数说明符只能用在函数标识符的声明中。

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

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.注意of的定义fahr是外部定义,因为fahr也是用extern声明的,但是of的定义cels是内联定义。因为cels有外部链接并被引用,外部定义必须出现在另一个翻译单元中(见 6.9);内联定义和外部定义是不同的,都可以用于调用。

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

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 中进行定义。


进一步阅读:

于 2013-04-02T16:39:22.920 回答