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

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声明。
...全文
693 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用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;
C++之程序结构,头⽂件,源代码⽂件 程序组织策略 程序组织策略 C++中建⽴代码⼯程时,通常包括三个部分:头⽂件,函数源代码⽂件,主程序源代码(即main()函数,可以调⽤函数源代码,完成程 序的整体流程与功能)。 头⽂件( 头⽂件(#include)常包含的内容: )常包含的内容: 函数原型 eg:void a(int temp); 使⽤ #define 或 const 定义符号常量 结构声明 类声明 模板声明 内联函数 说明: 1. 通常情况下,多个函数可能同时包括上述某些相同内容。如果每个函数中都对该内容进⾏声明,想要修改该内容就需要同时修改上述全部 声明,对后⾯的维护造成不必要的⿇烦。为避免上述问题,可以将相关的内容放在 头⽂件中,这样,要修改内容时,只需要在头⽂件中做 ⼀次修改就可以。 2. 函数定义,变量声明不能放在头⽂件中。例如,如果⼀个头⽂件中包含某⼀函数定义,然后在其他两个⽂件(属于同⼀个程序)中包含该 头⽂件,则同⼀个程序将包含同⼀个函数的两个定义(内联函数是特例),发⽣冲突。变量声明同函数定义。 3. 结构声明(struct),类声明(class)本⾝并不创建变量,⽽只是在源代码⽂件中声明变量时,告诉编译器如何创建该结构变量。同 理,模板声明指⽰编译器如何⽣成与源代码中函数调⽤相匹配的函数定义。 4. const 变量和内联函数有特殊的链接属性,可以放在头⽂件中,不会引起问题。 函数源代码⽂件( 函数源代码⽂件(.cpp或 或.cc): ): 函数源代码⽂件中,主要存放头⽂件中函数原型的具体实现。 使⽤⽅法:编写程序的时候,如果需要使⽤这些函数,则只需包含头⽂件,并将函数源代码⽂件添加到项⽬列表或make列表中 (Linux)。 注:在IDE中不要将头⽂件加⼊到项⽬列表中,也不要在源代码⽂件中使⽤#include来包含其他源代码⽂件,这样将会导致多声明。

33,322

社区成员

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

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