我已经阅读了一些与此主题相关的帖子,但无法彻底理清我的疑问。这可能是一个非常天真的问题。
我有一个标题文件inline.h
和两个翻译单元main.cpp
和tran.cpp
。
代码详情如下
#ifndef __HEADER__
#include <stdio.h>
extern inline int func1(void)
{ return 5; }
static inline int func2(void)
{ return 6; }
inline int func3(void)
{ return 7; }
#endif
#define <stdio.h>
#include <inline.h>
int main(int argc, char *argv[])
{
printf("%d\n",func1());
printf("%d\n",func2());
printf("%d\n",func3());
return 0;
}
//(note that the functions are not inline here)
#include <stdio.h>
int func1(void)
{ return 500; }
int func2(void)
{ return 600; }
int func3(void)
{ return 700; }
上面的代码用g ++编译,但不用gcc编译(即使你做了与gcc相关的更改,比如将代码更改为.c,不使用任何C ++头文件等)。显示的错误是“内联函数的重复定义 - func3”。
你能澄清一下编译器之间存在这种差异的原因吗?
此外,当您通过创建两个单独的编译单元(main.o
和tran.o
)并创建可执行文件a.out
来运行程序(g ++编译)时,获得的输出是:
500
6
700
为什么编译器会选择非内联函数的定义。实际上,由于#include
用于“添加”我预期的5,6,7
作为输出的内联定义。我的理解是在编译期间,因为找到了内联定义,函数调用将被内联函数定义“替换”。
您能否详细告诉我编译和链接的过程,这将导致我们500,6,700
输出。我只能理解输出6。
答案 0 :(得分:13)
这个答案分为以下几个部分:
duplicate definition of inline function - func3
问题以及原因。func3
的定义是重复而不是func1
。g++
可以成功复制问题
tran.cpp
重命名为tran.c
gcc -o main main.c tran.c
@ K71993实际上是使用旧的gnu89内联语义进行编译,这与C99不同。将tran.cpp
重命名为tran.c
的原因是告诉gcc驱动程序将其视为C
来源,而不是C++
来源。
引自GCC Document: An Inline Function is As Fast As a Macro的以下文字解释了为什么func3
是重复定义而不是func1
,因为func3
(而不是func1
)是外部可见符号(在GNU89内联语义中)
当内联函数不是静态函数时,编译器必须假定可能存在来自其他源文件的调用;由于全局符号只能在任何程序中定义一次,因此不能在其他源文件中定义该函数,因此无法集成其中的调用。因此,非静态内联函数总是以通常的方式自行编译。
如果在函数定义中指定 inline和extern ,则该定义仅用于内联。 在任何情况下,函数都不会自行编译,即使您明确地引用其地址也是如此。这样的地址成为外部引用,就像您只声明了该函数一样,并且没有定义它。
如果使用C99标准编译,即gcc -o main main.c tran.c -std=c99
,链接器会抱怨func1
的定义是重复的,因为C99中的 extern inline 是其他帖子和评论中提到的外部定义。
请参阅this有关GNU89 inline
和C99 inline.
g++
进行编译。使用g++
编译时,源程序被视为C++
源。由于func1
,func2
和func3
在多个翻译单元中定义且其定义不同,因此违反了One Defintion Rule of C++。由于当定义跨越多个转换单元时,编译器不需要生成恶意消息,因此行为未定义。
答案 1 :(得分:3)
编译错误是因为func1();
的重复定义因为func1()是使用extern inline定义的,所以它将产生一个外部定义。
但是,tran.c中还有一个外部定义,它会导致多个定义错误。
但是,func2()和func3()不会产生外部定义,因此没有重定义错误。
您可能需要查看here http://www.greenend.org.uk/rjk/2003/03/inline.html。
另外,请注意c ++和c对内联函数的处理方式不同,即使在c中,不同的标准(c89与c99)对内联函数的处理方式也不同。
答案 2 :(得分:2)
也许您应该发布实际代码。您显示的代码段无法编译:
extern inline int func1(void)
这没有任何意义。#define <stdio.h>
我认为你的意思是include
。一旦我修复了这些并用gcc编译,它编译得很好,我得到了以下输出
5
6
7
当我用g ++编译时,我得到了这个输出:
5
6
700
这是因为func3()在inline.h中不是静态的
答案 3 :(得分:1)
从C ++的角度来看,您的代码无效,因为它公然违反了One Definition Rule。您通过C ++编译器设置编译它的唯一原因是C ++编译器中的松散错误检查(它恰好是ODR中“无需诊断”的部分之一)。
您的代码无效C,因为它提供了函数func1
的重复外部定义。请注意,从C的角度来看,它是func1
,而不是func3
。您的func3
没有任何正式错误。您的func2
也可以,只要这两个定义在同一个翻译单元中永远不会“相遇”。
您可能从编译器获取不同诊断报告的一个可能原因是您的C编译器可能以某种非标准编译器特定方式支持inline
函数(C99之前的编译器或现代编译器)编译器以非标准“遗留”模式运行。)
坦率地说,我发现很难相信你从任何编译器收到关于func3
的错误报告,假设您发布的代码准确地代表了您尝试编译的内容。您发布的内容很可能是而不是真实代码。
答案 4 :(得分:0)
您看到的编译错误实际上是链接器错误。
gcc和g ++对static inline
的处理方式略有不同。 inline
是C ++的第一部分,然后在添加到标准C之前成为许多C编译器的扩展。标准语义可能不同,但它可能只是不同的实现。
它也可能与C ++代码中出现的一些疯狂的东西有关,这些代码可以消除重复的模板内容以及其他重复的东西。
答案 5 :(得分:0)
基本上Inline是GCC的后期条目(我的意思是c编译器)。 “[...]内联定义不提供函数的外部定义,并且不禁止另一个翻译单元中的外部定义。内联定义提供了外部定义的替代,翻译人员可以使用它来实现任何外部定义。调用同一翻译单元中的函数。未指定对函数的调用是使用内联定义还是外部定义。“ - ISO 9899:1999(E),C99标准,第6.7.4节