C++:使用 Makefile 和 object 声明的重复符号

C++: duplicate symbol using Makefile and object declaration


我在
中定义了一个结构 a.h

#IFNDEF
#define A_H
struct a_struct
{
int val;
int val_b;
}a;
#endif

并且 main.cppa.cpp 都包含 header

#include "a.h"

当我将 makefile 与以下内容一起使用时:

a.o: a.cpp a.h
    g++ -std=c++11 -c $<
main.o: main.cpp a.h
    g++ -std=c++11 -c $<
main: main.o a.o
    g++ -std=c++ $^ -o $@

出现编译错误:

duplicate symbol '_a' in:
    a.o
    main.o

是否在a.cppmain.cpp中重新定义了a? 有没有办法在不改变a.h的情况下解决这个问题?
如果那不可能,我该如何更改代码? 提前谢谢你:)

问题是 a.h 都声明了数据类型 struct a_struct 都声明了 a 作为该类型的变量。每个包含 header 的翻译单元——例如,基于 a.cpp 的翻译单元和基于 main.cpp 的翻译单元将因此声明其自己的 a,如果两个这样的翻译单元对同一个程序有贡献,然后导致未定义的行为。由于重复符号而被拒绝的程序是这种情况下 UB 的一种可能(并且相当普遍)的表现形式。

所以,

Is a being redefined in a.cpp and main.cpp?

是的。 a 的声明包含在每个源文件的翻译单元中,直接导致在每个源文件中定义 a。从技术上讲,这些声明本身并不是定义,但这有点 hair-splitting.

Is there a way to resolve this issue without changing a.h?

如果程序被修改,使得其中只有一个翻译单元 #includes a.h,无论是直接还是间接,那么它就不会有多个 a 的定义(来自它现在有它们的来源)。目前尚不清楚这对您来说是否是一个可行的解决方案,但这似乎值得怀疑。

In case that's not possible, how may I change the code?

最简单的更改是从 a.h 中删除 a 的声明:

#ifndef A_H
#define A_H
struct a_struct
{
int val;
int val_b;
};  // <-- the main change is here
#endif

如果您确实需要一个类型为 struct a_struct 的外部变量 a,那么您应该通过添加

在 header 中声明它 extern
extern struct a_struct a;

到header

在恰好一个 .cpp 文件中添加 a 的非(明确地)extern 声明:

struct a_struct a;

从它的名字来看,文件 a.cpp 似乎是后者的正确位置,但如果你不想修改它,那么你可以使用 main.cpp 代替。