链接 C 时出现“多重定义”错误,但仅在 MinGW 上

Eya*_*yal 2 c linker mingw

我的代码在 Linux 上编译时工作正常,但在 Windows 上的 MinGW 上失败。

\n

我正在将这四个文件编译在一起。 a.h是头文件,b.cc.cmain.c. 以下是内容。

\n
\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80> cat a.h\nenum {\n  BLACK,\n  WHITE\n} Colors;\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80> cat b.c\n#include "a.h"\n#include <stdio.h>\n\nvoid foo() {\n  printf("%d\\n", BLACK);\n}\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80> cat c.c\n#include "a.h"\n#include <stdio.h>\n\nvoid bar() {\n  printf("%d\\n", WHITE);\n}\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80> cat main.c\nvoid foo();\nvoid bar();\n\nint main() {\n  foo();\n  bar();\n  return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我用这个命令编译它们:

\n
gcc -c b.c; gcc -c c.c; gcc -c main.c; gcc -o colors b.o c.o main.o\n
Run Code Online (Sandbox Code Playgroud)\n

它在我的 Linux 桌面上运行良好,但在MinGW VM上失败。错误是:

\n
# gcc -c b.c; gcc -c c.c; gcc -c main.c; gcc -o colors b.o c.o main.o\nC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: c.o:c.c:(.bss+0x0): multiple definition of `Colors\'; b.o:b.c:(.bss+0x0): first defined here\ncollect2.exe: error: ld returned 1 exit status\n
Run Code Online (Sandbox Code Playgroud)\n

当我在 Linux 上运行时nmb.o我看到:

\n
\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80> nm b.o\n0000000000000004 C Colors\n0000000000000000 T foo\n                 U printf\n
Run Code Online (Sandbox Code Playgroud)\n

但在 MinGW 上,我看到了这一点:

\n
0000000000000004 B Colors\n
Run Code Online (Sandbox Code Playgroud)\n

不知何故,gcc 在每个系统上以不同的方式编译它们。那里B意味着我不能两次使用相同的符号,尽管在 Linux 上我得到了C并且它工作得很好。从联机帮助页来看nm

\n
           "B"\n           "b" The symbol is in the uninitialized data section (known as BSS).\n\n           "C" The symbol is common.  Common symbols are uninitialized data.  When linking, multiple common symbols may appear with\n               the same name.  If the symbol is defined anywhere, the common symbols are treated as undefined references.\n
Run Code Online (Sandbox Code Playgroud)\n

我该如何解决这个问题以便能够在 MinGW 上进行编译?

\n

Linux 使用 GCC 9;MinGW 可能使用 GCC 10。

\n

R..*_*R.. 6

您似乎创建了一个名为Colors未标记enum类型的变量:

enum {
  BLACK,
  WHITE
} Colors;
Run Code Online (Sandbox Code Playgroud)

您可能只想声明一个enum带有 tag 的类型Colors

enum Colors {
  BLACK,
  WHITE
};
Run Code Online (Sandbox Code Playgroud)

如果前者包含在多个源文件中,则它是无效的 C,因为它会产生Colors. 这是允许的,但不要求产生错误;不同系统的目标文件格式如何表示未初始化的全局变量导致其在链接时被检测为错误或不被检测为错误的实现细节。现代 GCC 即使在支持公共资源的目标上也不再使用公共资源,因此如果您更新到足够新的 GCC,这在 Linux 上也会出现错误。

  • GCC 10 默认为“-fno-common”,但早期版本默认为“-fcommon”。滥用 C 标准规则的代码(利用 C 标准中记录的“公共扩展”)现在无法在 GCC 10 下链接。(请参阅 [GCC 10 更改](https://gcc.gnu.org/gcc-10/changes .html) 在 C 部分下(在 C 系列部分之后):_GCC 现在默认为 `-fno-common`。因此,全局变量访问在各种目标上更加高效。在 C 中,现在具有多个暂定定义的全局变量导致链接器错误。使用“-fcommon”,此类定义会在链接期间以静默方式合并。_) (3认同)