【问题标题】:Compiler warning not generated for multiple definitions没有为多个定义生成编译器警告
【发布时间】:2014-12-02 20:16:57
【问题描述】:

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

例如:

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

在两个 .c 文件(比如 A.c 和 B.c)中给出了相同的定义,并在一个包含在 A.c 和 B.c 中的 .h 文件中进行了声明。但是为什么这没有给出编译时错误或者我怎样才能给他们编译错误

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

我正在使用 GCC 编译器 mingw

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

#ifndef H_H_
#define H_H_

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

【问题讨论】:

  • 如果有的话,你会得到一个链接器错误。你能举一个简短的例子来说明你正在做什么以及你是如何编译它的吗?
  • 无法重现:gist.github.com/sharth/054c243a5f621726fa8b 能否提供更多关于您使用的环境的信息?您的代码与我在该要点中发布的代码有何不同?
  • 即使链接器也没有给出任何错误,它看起来是第一个定义

标签: c gcc


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    链接器会检测到函数被定义了两次,并会产生一个“重复符号”错误。

    【讨论】:

    • 即使链接器也没有给出任何错误,它看起来是第一个定义
    • @Kunal 在这种情况下,我认为我们需要一个 MCVE 以便可以复制问题。此外,提及您正在使用的操作系统和工具链会很有帮助。
    • 请再次查看问题定义,因为我又添加了一个观察结果
    • @Kunal #ifndef 防止头文件被多次包含在单个 .c 文件中,但目前尚不清楚为什么会有任何影响,除了它确实表明头文件 被多次包含在一个或多个.c 文件中。
    【解决方案3】:

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

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

    【讨论】:

    • 请再次查看问题定义,因为我又添加了一个观察结果
    • 你能把链接器生成的警告信息贴出来吗?
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 2020-04-11
      • 2010-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-12
      • 1970-01-01
      相关资源
      最近更新 更多