我有以下文件结构:
X.h
#pragma once
#include "Y.h"
int ONE = 1;
int combine();
X.c
#include "X.h"
int combine()
{
return ONE + TWO;
}
Y.h
#pragma once
int TWO = 2;
Y.c
#include "Y.h"
MAIN.C
#include "X.h"
int main()
{
int fusion = combine();
return 0;
}
我收到以下错误:
LNK1169 one or more multiply defined symbols found
LNK2005 _ONE already defined in Main.obj
LNK2005 _TWO already defined in Main.obj
KLNK2005 _TWO already defined in Main.obj
这没有任何意义。如果我们从Main.c
开始,编译器必须包含X.h
。然后,编译器查找与X.h
关联的C文件。在X.c
内,它需要包含X.h
,但#pragma once
应该防范。然后它需要包含Y.h
。它查找C文件并查找Y.c
,其中包含Y.h
,但Y.h
已包含在内。然后,它返回到Main.c并且应该成功编译...但是没有。
我可以将/FORCE
添加到我的项目设置中,这使我的代码运行完美但仍然输出:
ONE has already been defined, second definition ignored.
答案 0 :(得分:5)
但是
#pragma once
应该防范
#pragma once
用于避免重复,包括单个翻译单元(在这种情况下为.c
文件),但它无法阻止多个定义跨越多个翻译单元。
您在ONE
文件中定义了全局变量TWO
和.h
,并且它们包含在多个翻译单元中并导致多个定义错误。
例如,最后,ONE
将在X.c
和Main.c
中定义,TWO
将在Y.c
,X.c
中定义, Main.c
。
您应在ONE
文件中声明TWO
和.h
(使用extern
),并在.c
文件中对其进行定义。
X.h
#pragma once
#include "Y.h"
extern int ONE;
int combine();
X.c
#include "X.h"
int ONE = 1;
int combine()
{
return ONE + TWO;
}
Y.h
#pragma once
extern int TWO;
Y.c
#include "Y.h"
int TWO = 2;
答案 1 :(得分:1)
#pragma once
仅防止在同一编译单元中包含两次相同的标头。在多个编译单元中定义相同的变量时,它不会阻止问题。
要了解错误的原因,让我们逐步了解每个编译单元在编译时的样子。
预处理后,X.c最终看起来像这样:
int TWO = 2;
int ONE = 1;
int combine();
int combine()
{
return ONE + TWO;
}
如您所见,它包含符号TWO
,ONE
和combine
的定义。
Y.c最终看起来像这样:
int TWO = 2;
它还定义了符号TWO
。
main.c看起来像这样:
int TWO = 2;
int ONE = 1;
int combine();
int main()
{
int fusion = combine();
return 0;
}
因此,它还包含TWO
和ONE
以及main
的定义。
因此,在编译之后,我们最终得到3个目标文件,其中三个都有TWO
的定义,其中两个定义了ONE
。当我们进行链接时,链接器会在ONE
的定义中看到TWO
和combine
的引用,并寻找这些符号'定义。由于它们在多个地方定义,因此会抛出错误并放弃。
您可以通过在Xh和Yh中声明 ONE
和TWO
以及定义 ONE
和{{1}来解决此问题在Xc和Yc中
答案 2 :(得分:0)
#pragma once
可防止在编译单个源模块时多次包含头文件。
这就是全部。
您的头文件包含在两个不同的源模块中。
该头文件在全局范围内声明并定义一个对象。
因此,两个源模块最终都会在全局范围内定义相同的对象。
重复符号定义的来源。
#pragma once
不能代替了解和理解C ++范围规则。