所以我正在阅读一些代码,并遇到了这个小片段:
//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吗?
答案 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标准的这一特定部分有些含糊,但提供了使用示例。)