C - 如果将包含在 header 中的符号重复,但如果包含在源文件中则工作正常

C - Duplicate symbol if put include in header, but works fine if include in source file

我有一个 header 文件,其中包含一个 int

数组

primes.h

#ifndef P_H
#define P_H
#include <inttypes.h>

uint64_t primes[] = {
    7,
    11,
};
#endif

lib.h 文件中: #include "primes.h"

lib.c 包括 lib.h

main.c 文件中: #include "lib.h"

然后会报错:duplicate symbol '_primes' in:

但是如果我将 #include "primes.h" 移动到 lib.c,它工作正常。 为什么将 include 放在源代码中 header 会有所不同?

您正在 h 文件中定义一个变量。这意味着您只能在一个编译单元中包含该 h 文件,即在一个 c 文件中。因此,当您将它包含在 lib.h 中并且如果 lib.h 包含在多个 c 文件中时,您就有麻烦了,即多个编译单元将定义数组变量 primes。那不行。

规则:不要在 h 文件中定义变量。始终在 c 文件中执行此操作。

(注意:可能会有例外,但这是黄金法则 - 除非您有充分的理由将变量放入 h 文件,否则请坚持使用)

查看此答案以获取操作说明:

当您包含一个文件时,包含将替换为文件内容(这种情况一直持续到没有更多包含为止)。

  • 如果 main.clib.c 都包含 lib.h,那么它们都有单独的 lib.h 编译副本。
  • 如果 lib.h 包括 primes.h,那么它们都有自己单独的 primes.h 编译副本。
  • 如果 primes.h 定义了一个数组,那么它们都有该数组的副本。
  • 如果它们在两个文件中都定义了相同名称的内容,则会出现重复定义错误。

解决此问题的最佳方法是仅在源文件中定义 primes 数组及其所有值(例如 lib.c),并且您需要使用 extern primes.h 中的关键字没有任何值来声明您的文件之一包含实际数组(在这种情况下您可以不指定大小)。请注意,使用 extern 关键字是对编译器的一种承诺,即存在一些包含实际数组的文件,这就是为什么您仍然需要源文件中的实际数组:

// primes.h
extern uint64_t primes[];

// lib.c
#include "primes.h"
uint64_t primes[] = {
    7,
    11,
};

// main.c
#include "primes.h"