【问题标题】:Struct with a value in a header file causing "duplicate symbol" linker error头文件中具有值的结构导致“重复符号”链接器错误
【发布时间】:2010-02-05 11:35:03
【问题描述】:

这是一个更大项目的缩减示例。你可以看到它here

我有一个包含系统时间函数限制的头文件。称之为 time_config.h。

#ifndef TIME_CONFIG_H
#define TIME_CONFIG_H

#define HAS_TIMEGM

#define SYSTEM_LOCALTIME_MAX             2147483647
#define SYSTEM_LOCALTIME_MIN            -2147483648
#define SYSTEM_GMTIME_MAX                2147483647
#define SYSTEM_GMTIME_MIN               -2147483648
const struct tm SYSTEM_MKTIME_MAX = { 7, 14, 19, 18, 0, 138, 0, 0, 0, 0, 0 };
const struct tm SYSTEM_MKTIME_MIN = { 52, 45, 12, 13, 11, 1, 0, 0, 0, 0, 0 };

#endif

然后是定义我的时间函数的头文件。称它为 mytime.h。它包括 time_config.h。

#ifndef MYTIME_H
#define MYTIME_H

#include "time_config.h"

#ifndef HAS_TIMEGM
time_t timegm(const struct tm*);
#endif

#endif

mytime.c 包含 mytime.h 并在必要时定义 timegm()。

我把它编译成一个目标文件...

gcc <a lot of warning flags> -I. -c -o mytime.o mytime.c

并将其链接到测试二进制文件中,t/year_limit.t.c 还包括 mytime.h。

gcc <a lot of warning flags> -I. mytime.o t/year_limit.t.c -o t/year_limit.t

出现哪些错误:

ld: duplicate symbol _SYSTEM_MKTIME_MAX in /var/folders/eJ/eJzTVP7oG7GVsKYHJtMprE+++TI/-Tmp-//ccMe5DXb.o and mytime.o
collect2: ld returned 1 exit status

因为time_config.h是在构建过程中通过系统探针生成的,所以将所有的值放在一个头文件中,甚至是多个头文件中会很方便。在构建过程中更改 .c 文件更加困难。

没有结构也可以正常工作。如何在头文件中声明最小/最大日期结构而不引起这种冲突?还是我编译链接不正确?

PS 这是 ANSI C89。

【问题讨论】:

    标签: c struct header linker


    【解决方案1】:

    在您的标题 (.h) 中,您需要:

    extern const struct tm SYSTEM_MKTIME_MAX;
    extern const struct tm SYSTEM_MKTIME_MIN;
    

    在您的实现 (.c) 中,您需要:

    const struct tm SYSTEM_MKTIME_MAX = { 7, 14, 19, 18, 0, 138, 0, 0, 0, 0, 0 };
    const struct tm SYSTEM_MKTIME_MIN = { 52, 45, 12, 13, 11, 1, 0, 0, 0, 0, 0 };
    

    【讨论】:

      【解决方案2】:
      const struct tm SYSTEM_MKTIME_MAX = { 7, 14, 19, 18, 0, 138, 0, 0, 0, 0, 0 };
      

      上面声明并定义了对象SYSTEM_MKTIME_MAX;包含多个标头会导致多个定义。

      在标头中放入extern,并将定义放入实现文件中。

      【讨论】:

      • 我认为#ifndef TIME_CONFIG_H 可以防止多重包含?
      • 仅在同一个编译单元中 - 这些是定义符号的不同编译单元
      • @Schwern:确实如此,但是您的 SYSTEM_MKTIME_MAX 在不同翻译单元(即源文件)中定义了两次,这就是链接器抱怨的原因。
      • 我担心这就是答案。头文件由探测系统的程序生成。必须更改 .c 文件也会使构建复杂化。有没有办法保留在头文件中?
      • 用C++编译器编译? (好吧,开个玩笑)
      【解决方案3】:

      C 中的常量具有外部链接,因此应在 .c 文件中定义。

      在 C++ 中,它们具有内部链接,因此可以在标题中定义。

      【讨论】:

        【解决方案4】:

        标头只能包含声明。所以将标题更改为:

        extern const struct tm SYSTEM_MKTIME_MAX;
        

        然后在 cpp 中赋值

        const struct tm SYSTEM_MKTIME_MAX = {...
        

        【讨论】:

        • 注意,我们讨论的是 C,而不是 C++(其中常量具有内部链接,因此示例在 C++ 中有效)。所以可能不是cpp,而是c文件。
        • @Alexander Poluektov cpp 和 c 都不支持两次声明,所以关键字是“extern”
        • 1) 你混淆了声明和定义。两次声明在 C 和 C++ 中是完全可以接受的both
        • 2) const 的“两次定义”在 C++ 中是完全可以接受的,因为常量具有内部链接。
        猜你喜欢
        • 2013-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-07
        • 2017-11-21
        • 1970-01-01
        • 2012-04-10
        相关资源
        最近更新 更多