为什么结构的双重声明会导致编译错误,而函数的双重定义会导致链接错误?
4 回答
因为函数定义在链接时包含在可执行文件中,但声明或语法检查都在编译时完成
当您调用任何函数并且编译器无法找到函数的声明时,还要考虑一件事,然后它将生成警告为implicit declaration of func()
.
为了删除这个警告信息,我们提供了 func 的前向声明,int func();
它编译时没有任何警告信息。
你认为为什么会发生这种情况?发生这种情况是因为编译器没有找到该func()
符号。根据语言语法使代码无错误完全取决于编译器。
但是最终可执行文件的构建是在链接时完成的,然后链接器开始寻找函数定义func()
,如果找到则很好,如果没有.. 然后Linker error
could not have resolved external symbol _func()
注意:任何外部符号都在链接时解析
在 gcc 上仅用于编译使用:(这可能因编译器而异)
gcc -Werror -c test.c
--> 生成test.o
文件
然后尝试链接它并使其可执行
gcc -Werror -o test test.o
-->test
是可执行的
该标准没有说明何时应该报告错误 - 这取决于编译器,但基本上是因为那是错误被捕获的时间。
首先,编译器解析文件。很容易看出 a struct
orclass
是否在同一个翻译单元中被多次定义(只是这是一个错误,在翻译单元之间你可以有多个类类型定义),因为它处理那个翻译单元。
其次,它将目标文件链接在一起(链接)。直到现在它才能知道同一个符号被导出了多次,因为那是错误发生的时候。
编译程序时,编译器需要知道要使用的结构的确切定义。但是我们只需要在尝试链接程序时才知道要使用哪个确切的功能。
因此,如果一个结构被定义了两次,编译器在编译过程中会感到困惑,因此会在编译时抱怨。
对于编译期间的函数,您可以有多个定义,但只有在链接期间才会出现混淆,因此在链接期间会出现问题。
你说的不一定是真的。
如果你在头文件中“内联”函数定义,然后在编译单元中写入它的定义,你会得到一个错误
...already has a definition.
您所指的情况是当两个不同的编译单元定义(或查看定义)相同的函数时,因此在任何单个编译单元中都没有编译错误,而是它们的组合导致了链接错误。
顺便注意一下,这就是关键字inline
真正发挥作用的地方。对于头文件中定义的非模板函数,如果使用inline
关键字,则意味着定义该函数时可以存在多个编译单元。它实际上并不能保证编译器会内联它。