了解C99中的“外部内联”调用

时间:2019-06-04 19:43:08

标签: c inline c99 linkage

所以我正在阅读一些代码,并遇到了这个小片段:

//file.h

extern inline void foo();

具有如下所示的实现:

//file.c
MyType_t instance;
inline void foo()
{
    instance.someField++;
}

也许我可能误解了一些东西,但是在我看来,作者似乎想拥有一个外部可见的功能,该功能也为inline(我相信默认情况下具有内部链接)。因为它是一个很小的修饰符函数,所以我认为其目的是利用内联替换来避免函数开销(这是有意义的,因为它在嵌入式平台上运行)。但是这段代码实际上有资格进行内联替换吗?

我的理解是inline规定编译器不会抱怨多个定义(按照this link),而函数may be eligible for inline substitution(作为类似函数的替代方法)宏)。

但是,在这种情况下,由于定义不在标题中,因此内联函数仍然只有一个“副本”,因此它不适合在包含file.h的文件中进行内联替换(如据我所知)。

(来自上面的第二个链接):

  

编译器至少必须已经看到该函数的定义。但是,如果您有一个经典的大C项目,其功能是在不同的编译单元中实现的,那么编译器将无法为您完成该集成。因此,您必须将此类候选函数的实现放在头文件中。

因此,剩下的唯一属性是编译器不会抱怨乘法定义的符号,因此它可能在不同的编译单元中以不同的方式定义。尽管在这种情况下并非如此,但该符号只为记录定义一次。

所以我的问题的关键是:我是否正确地得出结论,认为此内联实际上并没有比以下代码更好的用途:

//file.h
extern void foo();

//file.c
MyType_t instance;
void foo()
{
    instance.someField++;
}

如果作者希望使其有资格进行内联替换,解决方案将是put the inline declaration and function body in the header吗?

1 个答案:

答案 0 :(得分:3)

C99内联函数与C ++内联函数不同。

它们没有合并。如果您未指定static,则应该提供外部定义。

对内联函数f执行此操作的方式是在以下位置提供extern声明(例如int f(void);extern int f(void);extern inline int f(void);)翻译单元,其中还提供了inline的{​​{1}}定义(例如f)。

顺序并不重要。

inline f(void){ return 42; }

提供外部定义,就像

inline int f(void) { return 42; }
int f(void);

确实。

仅具有内联声明/定义而没有extern声明的转换单元将不会提供extern定义:

int f(void);
inline int f(void) { return 42; }

通常,您将在示例中的标头中包含一个内联定义,然后实例化它,将包含标头并提供extern声明。从技术上讲,在声明中包括 inline int f(void); //^if an inline decl is present a definition MUST follow or else you get a diagnostic inline int f(void) { return 42; } inline int f(void); //a pointless but legal redeclaration extern并不是必须的,但很显然,声明的目标是实例化内联函数的外部定义。

更多信息,位于6.7.4p7。 (我发现C标准的这一特定部分有些含糊,但提供了使用示例。)