没有为多个定义生成编译器警告

时间:2014-12-02 20:16:57

标签: c gcc

我遇到的问题是具有相同签名的函数在两个.c文件中定义,并且没有给出编译时错误。我在.h文件中包含了声明,它包含在.c文件中。

例如:

int add(int x, int y) { return x+y;}

两个.c文件(Say A.c和B.c)中的相同定义和一个.h文件中的声明,该文件包含在A.c和B.c中。但是为什么这不会给出编译时错误或者如何让它们给出编译错误

即使Linker没有给出任何错误,它看起来是第一个定义

我正在使用GCC编译器mingw

我发现了另一种模式。 如果我在头文件中使用它

#ifndef H_H_
#define H_H_

链接器未发出警告警告但如果我不使用此链接器会发出预期的警告。

4 个答案:

答案 0 :(得分:1)

编译器不会整体分析您的程序。它一次只处理一个.c文件。如果.h文件中的声明与.c文件中的定义匹配,那么就编译器而言,一切都很好。

链接器将检测到该函数已定义两次并将生成"重复符号" 错误。

答案 1 :(得分:1)

编译器将每个源文件与另一个文件区分开来。编译器将头文件的内容包含到A.c中,然后从A.c生成一个目标文件A.obj. A.obj文件将包含在A.c中定义的变量和函数的符号。另一方面,编译器将在不检查A.c或任何其他源文件内容的情况下处理B.c.它将首先将头文件包含到B.c中,然后生成B.obj,它还包括B.c中定义的变量和函数的符号。

因此,编译时不会出现错误,因为编译器未检测到函数复制。检查符号一致性并且不存在重复是链接器作业。链接器将获取所有生成的目标文件以生成可执行文件。链接器必须为每个符号分配唯一的内存地址。例如,在代码中,如果有一个点(让我们在主函数中说),其中调用了A.c的函数,实际上,这被转换为跳转到该函数所在的内存中的地址。现在,假设两个具有相同签名的函数在可执行文件中共存,并且每个符号具有不同的地址。然后,处理器如何确定您打算在程序中准确调用哪个函数。因此,如果链接器找到一个重复的符号,它将发出错误信号。

答案 2 :(得分:1)

这种情况是未定义的行为,无需诊断。

请参阅链接器的文档,了解它是否有任何报告多个函数定义的选项。

答案 3 :(得分:0)

正如@ Matt-McNabb所说:请参阅您的链接器文档。

我能想到的另一个原因是链接器二进制文件比较两个函数,发现它们是相同的,并忽略一个。您可以通过稍微更改代码来检查,例如“return y + x”。