如何在C99多文件项目中声明内联函数?

如何在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" 对于同

我想在用c99编译的项目中定义一个内联函数。我怎么做? 当我在头文件中声明函数并在.c文件中给出详细信息时,其他文件无法识别该定义。当我将显式函数放在头文件中时,我遇到了一个问题,因为所有使用它的.o文件都有一个定义副本,所以链接器会给我一个“多定义”错误

我想做的是:

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只是忽略
    内联
    关键字

术语“翻译单元”包括源文件(lib1.c)和包含的所有头文件。这意味着可以将其放置在
header.h
中。编译器已损坏,或者函数被声明为
extern
,这将对此进行解释。多个定义可能源于在头文件中声明函数的
extern
。这将迫使每个翻译单元发出函数的副本。@Lindydancer:当然。但我要说的是,即使只有
inline
声明,某些编译器也会生成符号。我将补充一些关于特定编译器的评论。谢谢Jens。它工作正常(GCC4.4.5,带有标志std=gnu99和std=c99)。@JensGustedt,与在所有情况下在头文件中简单使用
静态内联
相比,使用“新方法”有什么好处吗?@Mike,是的,在我的POV中有两种。首先,如果编译器决定不内联,就不要用函数的副本破坏可执行文件。然后,函数可以通过其地址唯一地识别,所有指向它的指针将进行相等的比较,即使它们来自不同的编译单元。顺便说一句,仅仅声明它
static
static inline
完全相同,
inline
几乎没有用处。现代编译器不会自行决定是否内联,程序员在优化这一点上出了名的差劲。有趣的是,头由#ifndef保护。但我认为它不起作用,因为编译器仍然将头放在每个.o文件中。