如何在C99多文件项目中声明内联函数?
我想在用c99编译的项目中定义一个内联函数。我怎么做? 当我在头文件中声明函数并在.c文件中给出详细信息时,其他文件无法识别该定义。当我将显式函数放在头文件中时,我遇到了一个问题,因为所有使用它的.o文件都有一个定义副本,所以链接器会给我一个“多定义”错误 我想做的是:如何在C99多文件项目中声明内联函数?,c,linker,c99,inline-functions,C,Linker,C99,Inline Functions,我想在用c99编译的项目中定义一个内联函数。我怎么做? 当我在头文件中声明函数并在.c文件中给出详细信息时,其他文件无法识别该定义。当我将显式函数放在头文件中时,我遇到了一个问题,因为所有使用它的.o文件都有一个定义副本,所以链接器会给我一个“多定义”错误 我想做的是: header.h inline void func() { do things... } lib1.c #include "header.h" ... lib2.c #include "header.h" 对于同
header.h
inline void func()
{
do things...
}
lib1.c
#include "header.h"
...
lib2.c
#include "header.h"
对于同时使用lib1.o和lib2.o的实用程序,我认为在头文件中定义和声明函数时不需要使用内联词,编译器通常默认情况下将其视为内联函数,除非它太长,在这种情况下,它将足够聪明地将其视为普通函数 我认为多重定义可能是由于头文件中缺少Include保护造成的 您应该在标题中使用如下内容:
#ifndef HEADERNAME_H
#define HEADERNAME_H
void func()
{
// do things...
}
#endif
如果单独使用,则在C99
inline
中,需要在使用该函数的同一翻译单元中定义该函数(因此,如果在lib1.c中使用该函数,则必须在lib1.c中定义该函数)
您还可以将方法声明为静态内联
(并将定义放在两个源文件之间共享的头文件中)。这避免了多定义问题,并允许编译器跨使用该文件的所有翻译单元内联该文件(如果仅在一个翻译单元中声明函数,则可能无法实现)
请参阅:不幸的是,在这一点上,并不是所有编译器都完全符合C99,即使它们声称自己会遵守 这样做的一种方法是
// header file. an inline definition alone is
// not supposed to generate an external symbol
inline void toto(void) {
// do something
}
// in one .c file, force the creation of an
// external symbol
extern inline void toto(void);
例如,新版本的gcc可以很好地解决这个问题
对于其他编译器(假装器),您可以通过定义如下
#ifdef PRETENDER
# define inlDec static
# define inlIns static
#else
# define inlDec
# define inlIns extern
#endif
// header file. an inline declaration alone is
// not supposed to generate an external symbol
inlDec inline void toto(void) {
// do something
}
// in one .c file, force the creation of an
// external symbol
inlIns inline void toto(void);
编辑:
据我所知,支持C99(通常为选项-std=C99
)的编译器
- gcc(版本>=4.3 IIRC)实现
正确的
内联
型号
- pcc也是正确的
- ggc<4.3需要一个特殊选项来 实施正确的模式,, 否则,他们会使用自己的模型 这将导致多个定义的 如果你不小心的话
- icc只是在每个单元中发射符号 如果你不特别小心的话。但是 这些符号是“弱”符号,所以 它们不会产生冲突。他们 把你的密码放大
- opencc,AFAIR,遵循旧的特定于gcc的模型
- clang根本不会为
函数发出符号,除非您有内联
声明并且在一个编译单元中使用函数指针extern
- tcc只是忽略
内联
关键字
header.h
中。编译器已损坏,或者函数被声明为extern
,这将对此进行解释。多个定义可能源于在头文件中声明函数的extern
。这将迫使每个翻译单元发出函数的副本。@Lindydancer:当然。但我要说的是,即使只有inline
声明,某些编译器也会生成符号。我将补充一些关于特定编译器的评论。谢谢Jens。它工作正常(GCC4.4.5,带有标志std=gnu99和std=c99)。@JensGustedt,与在所有情况下在头文件中简单使用静态内联
相比,使用“新方法”有什么好处吗?@Mike,是的,在我的POV中有两种。首先,如果编译器决定不内联,就不要用函数的副本破坏可执行文件。然后,函数可以通过其地址唯一地识别,所有指向它的指针将进行相等的比较,即使它们来自不同的编译单元。顺便说一句,仅仅声明它static
与static inline
完全相同,inline
几乎没有用处。现代编译器不会自行决定是否内联,程序员在优化这一点上出了名的差劲。有趣的是,头由#ifndef保护。但我认为它不起作用,因为编译器仍然将头放在每个.o文件中。