C 内联函数多重定义

C 内联函数多重定义,c,gcc,inline,C,Gcc,Inline,我有以下三个文件: 内联_头.h 资料来源1.c 资料来源2.c 当我只使用gcc source2.c编译source2.c时,它会编译。但是,当我尝试使用gcc source1.c source2.c进行编译时,会出现如下多定义错误: /tmp/cchsOaHF.o: In function `func1': source2.c:(.text+0x0): multiple definition of `func1' /tmp/ccEyUW0T.o:source1.c:(.text+0x0):

我有以下三个文件:

内联_头.h 资料来源1.c 资料来源2.c 当我只使用
gcc source2.c
编译
source2.c
时,它会编译。但是,当我尝试使用
gcc source1.c source2.c
进行编译时,会出现如下多定义错误:

/tmp/cchsOaHF.o: In function `func1':
source2.c:(.text+0x0): multiple definition of `func1'
/tmp/ccEyUW0T.o:source1.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
我在Ubuntu 14.04上使用GCC4.8.4进行编译


我试着查了一下,发现了一个类似的问题。然而,在他的例子中,错误是由重新定义内联函数引起的。在我的情况下,我没有重新定义它(或者至少没有明确地…。

如果您希望将此类函数放在头中,它也必须是静态的

static inline int func1() {
    return 1;
}
这将导致符号对于每个编译单元(文件)都是本地的,从而避免任何链接器错误

此外,gcc:

当内联函数不是静态函数时,编译器必须假定 可能有来自其他源文件的调用;因为它是全球的象征 在任何程序中只能定义一次,该函数不得 在其他源文件中定义,因此其中的调用无法 集成的因此,始终编译非静态内联函数 以惯常的方式独自一人


将source1.c编译成source1.o时,它包含
func1
的定义。类似地,当您将source2.c编译成source2.o时,它还包含
func1
的定义。因此,当链接source1.o和source2.o时,会出现多定义错误

include防护不阻止这种情况的原因是source1.c和source2.c都是单独编译的。在单个编译单元中仅包含保护帮助

如果这不是内联函数,您应该在头文件中声明:

int func1();
然后将定义放在一个源文件中

但是,您将函数定义为
inline
。因此,您还需要将其声明为
静态
,以便每个编译单元都有自己的函数副本

编辑:

发生多定义错误是因为默认情况下您是在C89模式下编译的,
inline
不是该标准版本的一部分。因此,gcc似乎基本上忽略了这个关键字

如果使用此代码在C99或C11模式下使用
-std=C99
=std=C11
进行编译,实际上会得到一个“未定义引用”错误。C标准第6.7.4p7节规定了以下内容:

任何具有内部链接的函数都可以是内联函数。对于具有外部链接的函数,以下限制适用:如果函数是用
内联
函数说明符声明的,则它也应在同一翻译单元中定义。如果翻译单元中某个函数的所有文件范围声明都包含
inline
函数说明符,而不包含
extern
,则该翻译单元中的定义是
inline
定义。内联定义不为函数提供外部定义,也不禁止在其他翻译单元中使用外部定义。内联定义提供了外部定义的替代方法,转换器可以使用外部定义在同一翻译单元中实现对函数的任何调用。未指定对函数的调用是使用内联定义还是外部定义

这意味着一个只有
内联
的函数实际上并不提供一个可以调用的函数的定义。在您的情况下,您需要添加
静态
存储类说明符,以强制在每个文件中进行本地定义


有趣的是,如果您使用
-O1
-std=c99
编译此代码,gcc将物理内联函数,它将编译并干净地运行。

谢谢,我的印象是#ifndef守卫阻止了头文件在整个程序中重复。OP中描述的行为是否与内联函数和变量(不是静态的或本地链接的)遵守ODR相矛盾,因此只要它们同意,每个翻译单元可以有一个定义?请参见“说明2”下的内容。事实上,它需要这样做,因为编译器在编译时必须在每个翻译单元中看到def以内联注入函数代码。@DonSlowik使用
inline
不能保证函数是物理内联的。这只是对编者的一个提示。因为这是C++,所以实际上你想看看C标准的第7.7.4节。在C++中,它应该很好,因为我给出的原因。知道C和C++之间的行为差异是很好的。@ dBuw,但是,你所给的链接的第一个代码示例中的段落不是说OP的代码应该工作吗?这里的最后一句话似乎说,您可以完全执行操作代码的功能。请参阅
/tmp/cchsOaHF.o: In function `func1':
source2.c:(.text+0x0): multiple definition of `func1'
/tmp/ccEyUW0T.o:source1.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
static inline int func1() {
    return 1;
}
int func1();