关于头文件被多次包含后引起的符号重定义错误

woncomp 2010-10-24 02:21:28
考虑这样一个简单的项目,包含1个main文件,一个头文件,一个cpp文件。
---- main.cpp

#include "head.h"

int main()
{
func1();
}

---- head.h

//#pragma once
#ifndef _HEADDDD
#define _HEADDDD

#include <iostream>
using namespace std;

int g_number;
void func1();

#endif

---- func.cpp

#include "head.h"

void func1()
{
cout<<"func1 "<<g_number<<endl;
}


头文件head.h被包含了两次,结果导致g_number变量产生了重定义。

那么我想问问,#ifndef _HEADDDD这样的条件编译,或者#pragma once,到底是用来解决什么的?

如何才能在头文件中定义变量?(比如许多const变量肯定是想要在项目中的不同地方使用的)请不要告诉我写在cpp里然后用extern声明。
...全文
621 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
liaozcYAOBOT 2012-08-03
  • 打赏
  • 举报
回复
我自己的体验说一下,编译有很多步骤,头文件的编译会被生成在头文件名作用域下的一序列信息,如类型,变量,函数等。而条件编译就是避免被重复的编译,解决类型重定义和提高编译速度。当如果头文件有lz说的有定义
变量和函数,这些变量和函数就会被生成全局变量,当被多次包含时,就会多次生成全局变量,当链接时,编译器
不能确定你的全局变量是哪一个,故出现链接错误。
wasx1 2010-10-25
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 shexinwei 的回复:]
C/C++ code

//#pragma once
#ifndef _HEADDDD //建议改为: #ifndef HEAD_H
#define _HEADDDD

#include <iostream>
using namespace std;

extern int g_number; //头文件中一般只声明,在.cpp文件……
[/Quote]
一般编程都是采用的这种方法。
冻结 2010-10-25
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 woncomp 的回复:]
补充问题:

1 既然有条件编译指令了,那么为什么中间的内容还是在不同模块被编译了2次最终导致符号重复?

2 假设我想在头文件里定义一个全局变量,在不同的cpp文件之间交叉访问,用extern的话显然不能方便的使用。因为我不知道应该在哪个cpp文件才去定义那个没有extern的实体。
[/Quote]

透过本质看现象:
1.
int g_number; // 定义式,不管你放在哪里,它也是定义式。定义式需要分配内存,所以一个变量的定义式应该只有一个,而且只能有一个。你的头文件被多处包含,相当于定义了多个定义式,所以报错是必然的。
extern int g_number; // 声明式,不分配内存,可以有N多个。放在头文件中,被包含多次,无所谓。

2.
如果你有一个头文件叫"head.h",放你的声明式。
一般会有一个cpp文件叫"head.cpp",放你的定义式。
这样,不存在你想的不方便。
woncomp 2010-10-25
  • 打赏
  • 举报
回复
别差不多啊 具体差多少?

学程序眼里揉不得沙子啊。。
ForestDB 2010-10-25
  • 打赏
  • 举报
回复
差不多就是LZ那意思。
woncomp 2010-10-25
  • 打赏
  • 举报
回复 1
今天突然想通了。。

我收到java影响过深,下意识的认为一个文件中的变量要想在另一个文件中使用就必须import这个文件,而C加加中根本不是这样。想要使用本文件中未声明的变量,我根本不必关心它是在哪个文件定义的,甚至不必知道他是否真的被定义过,只要不负责任的声明为外部变量就行,到时候链接器会替我找那变量的本体所在。。。


关于条件编译我想向高手请教一下,是否可以这样理解:“条件编译只在同一个编译单元中有效”

假如我有src1.cpp何src2.cpp同时包含了head.h,虽然head.h中有条件编译语句,但是src1.cpp和src2.cpp属于不同的编译单元,所以它会在src1.cpp和src2.cpp中分别编译一次。虽然编译的时候没有冲突,但是到了链接的时候,冲突就显现出来了。
woncomp 2010-10-24
  • 打赏
  • 举报
回复
补充问题:

1 既然有条件编译指令了,那么为什么中间的内容还是在不同模块被编译了2次最终导致符号重复?

2 假设我想在头文件里定义一个全局变量,在不同的cpp文件之间交叉访问,用extern的话显然不能方便的使用。因为我不知道应该在哪个cpp文件才去定义那个没有extern的实体。
aizibion 2010-10-24
  • 打赏
  • 举报
回复
既然你都希望const变量在头文件中定义方便到处引用,你为何不把它改为const类型的,你试过吗?

还是自己动手吧,常量的定义当然可以放在头文件里面。
shexinwei 2010-10-24
  • 打赏
  • 举报
回复

//#pragma once
#ifndef _HEADDDD //建议改为: #ifndef HEAD_H
#define _HEADDDD

#include <iostream>
using namespace std;

extern int g_number; //头文件中一般只声明,在.cpp文件中定义
void func1();

#endif

冻结 2010-10-24
  • 打赏
  • 举报
回复
其它法暂未发现,请理解变量的声明式和定义式
冻结 2010-10-24
  • 打赏
  • 举报
回复
h中extern int g_number;cpp中int g_number;

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧