在C中使用`inline`关键字有什么用?

xiv*_*r77 36 c inline c99

我在stackoverflow中读了几个关于inlineC的问题,但仍然不清楚.

  1. static inline void f(void) {}没有实际的区别static void f(void) {}.
  2. inline void f(void) {}在C中不能像C++那样工作.它在C中如何工作?
  3. 究竟做了extern inline void f(void);什么?

我从来没有真正inline在我的C程序中找到关键字的使用,当我在其他人的代码中看到这个关键字时,它几乎总是static inline,我认为没有区别static.

Wed*_*shi 22

AC代码可以通过两种方式进行优化:代码大小和执行时间.

内联函数:

gcc.gnu.org说,

通过声明内联函数,您可以指示GCC更快地调用该函数.GCC可以实现这一目标的一种方法是将该函数的代码集成到其调用者的代码中.这通过消除函数调用开销使执行更快; 此外,如果任何实际参数值是常量,则它们的已知值可能允许在编译时进行简化,因此不需要包括所有内联函数的代码.对代码大小的影响不太可预测; 根据具体情况,具有函数内联的目标代码可以更大或更小.

因此,它告诉编译器将函数构建到使用它的代码中,以便缩短执行时间.

如果声明像重复执行的设置/清除标志或某些位切换这样的小功能inline,它可以在时间方面产生很大的性能差异,但代价是代码大小.


非静态内联和静态内联

再次提到gcc.gnu.org,

当内联函数不是静态的时,编译器必须假定可能存在来自其他源文件的调用; 由于全局符号只能在任何程序中定义一次,因此不能在其他源文件中定义该函数,因此无法集成其中的调用.因此,非静态内联函数总是以通常的方式自行编译.


外部内联?

同样,gcc.gnu.org,说明了一切:

如果在函数定义中同时指定了inline和extern,则该定义仅用于内联.在任何情况下,函数都不会自行编译,即使您明确地引用其地址也是如此.这样的地址成为外部引用,就像您只声明了该函数一样,并且没有定义它.

内联和外部的这种组合几乎具有宏的效果.使用它的方法是将函数定义放在带有这些关键字的头文件中,并将定义的另一个副本(缺少内联和外部)放在库文件中.头文件中的定义导致对函数的大多数调用都被内联.如果函数的任何使用仍然存在,则它们引用库中的单个副本.


把它们加起来:

  1. 因为inline void f(void){}, inline定义仅在当前翻译单元中有效.
  2. 对于static inline void f(void) {} 由于存储类是static,所述标识符具有内部联动和inline定义在其他翻译单元不可见的.
  3. 对于extern inline void f(void); 存储类extern,标识符具有外部链接,内联定义也提供外部定义.


M.M*_*M.M 20

注意:当我在这个答案中谈论.c文件和.h文件时,我假设您已经正确布置了代码,即.c文件只包含.h文件.区别在于.h文件可以包括在多个翻译单元中.

static inline void f(void) {}没有实际的区别static void f(void) {}.

在ISO C中,这是正确的.它们的行为是相同的(假设你当然不会在相同的TU中以不同的方式重新声明它们!)唯一的实际效果可能是使编译器以不同的方式进行优化.

inline void f(void) {}在C中不能像C++那样工作.它在C中如何工作?究竟做了extern inline void f(void);什么?

这是通过解释这个答案,也该线程.

在ISO C和C++中,您可以inline void f(void) {}在头文件中自由使用- 尽管出于不同的原因!

在ISO C中,它根本不提供外部定义.在ISO C++中,它确实提供了外部定义; 但是C++有一个额外的规则(C没有),如果有一个inline函数的多个外部定义,那么编译器会将其排序并选择其中一个.

extern inline void f(void);.cISO C 中的文件意味着与inline void f(void) {}头文件的使用配对.它导致函数的外部定义在该翻译单元中发出.如果您不这样做,那么就没有外部定义,因此您可能会收到链接错误(未指定是否f对外部定义进行任何特定的链接调用).

换句话说,在ISO C中,您可以手动选择外部定义的位置; 或者static inline到处使用完全压制外部定义; 但是在ISO C++中,编译器会选择外部定义的位置和位置.

在GNU C中,情况有所不同(下面有更多内容).

为了使事情进一步复杂化,GNU C++允许你编写static inline一个extern inlineC++代码......我不想猜测究竟是什么

我从来没有真正在我的C程序中使用inline关键字,当我在其他人的代码中看到这个关键字时,它几乎总是静态内联

许多程序员不知道他们在做什么,只是把看起来有用的东西放在一起.另一个因素是您正在查看的代码可能是为GNU C而不是ISO C编写的.

GNU C中,plain的inline行为与ISO C不同.它实际上发出一个外部可见的定义,因此从两个转换单元中包含一个.h带有普通inline函数的文件会导致未定义的行为.

因此,如果编码器想要inline在GNU C中提供优化提示,则static inline需要.既然static inline可以在ISO C和GNU C中使用,那么人们最终会为此做好准备,并且看到它似乎可以正常工作而不会出错.

,我认为只有静态没有区别.

不同之处仅在于为编译器提供速度超过大小的优化提示.使用现代编译器,这是多余的.

  • 我刚刚阅读了最近的 C 标准草案,其中指出“如果翻译单元中函数的所有文件范围声明都包含不带 extern 的内联函数说明符,那么该翻译单元中的定义就是内联定义。内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中使用外部定义。” 如果我满足内联定义的要求,这是否意味着不需要`extern` 声明? (2认同)

Moh*_*ain 5

自C11规范的6.7.4功能说明符起

6用内联函数说明符声明的函数是内联函数。使函数成为内联函数意味着对函数的调用应尽可能快。138)这些建议有效的程度是 实施定义的139)

138)例如,通过使用常规函数调用机制的替代方法,例如内联替换。内联替换不是文本替换,也不创建新函数。因此,例如,在函数主体内使用的宏扩展使用其在函数主体出现时的定义,而不是在调用函数的位置进行的定义;标识符是指主体所在范围内的声明。同样,该函数具有一个地址,而不管除外部定义之外发生的内联定义的数量如何。

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

它建议编译器该函数被广泛使用,并要求更喜欢调用该函数的速度。但是对于现代智能编译器,这可能或多或少无关紧要,因为编译器可以决定是否应该内联函数,并且可以忽略用户的内联请求,因为现代编译器可以非常有效地决定如何调用函数。

static inline void f(void) {}与并无实际差异static void f(void) {}

因此,对于大多数现代编译器来说,是的。对于任何编译器,都没有实际/可观察到的输出差异。

inline void f(void) {}在C中不能像C ++那样工作。它在C中如何工作?

在C ++中任何地方都可以内联的函数必须在C ++中的任何地方都可以内联,并且链接程序不会抱怨多个定义错误(定义必须相同)。

extern内联void f(void)实际执行什么操作;做?

这将提供与的外部链接f。因为f可能存在于其他编译单元中,所以编译器可以选择不同的调用机制来加快调用速度,或者可以inline完全忽略。