【问题标题】:C - Duplicate symbol if put include in header, but works fine if include in source fileC - 如果将包含包含在标头中,则重复符号,但如果包含在源文件中则工作正常
【发布时间】:2020-04-30 05:12:03
【问题描述】:

我有一个包含 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 放入源和标头中会有所作为?

【问题讨论】:

  • 您的lib.c 可能还包括lib.h,对吗?
  • @JonathanLeffler 我知道 extern,只是好奇为什么包含在源文件中可以使它工作。
  • 那么您应该再次阅读该链接。使用extern 和放置定义的位置密切相关。

标签: c include header-files


【解决方案1】:

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

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

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

// primes.h
extern uint64_t primes[];

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

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

【讨论】:

    【解决方案2】:

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

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

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

    有关操作说明,请参阅此答案:https://stackoverflow.com/a/1433387/4386427

    【讨论】:

    • 感谢编译单元,我对此一无所知。那么在源文件中包含primes.h 是错误的吗?我不想使用extern,因为我需要创建primes.c 在其中定义变量。
    • @TomSawyer 当一个程序由多个 c 文件组成时,每个 c 文件都是一个“编译单元”。它们被一一编译,然后链接在一起形成整个程序。我不明白你为什么说“我不想使用 extern ...”?这就是这样做的方法!在 c 文件中定义变量并将 extern 声明放在 h 文件中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多