C/C++重复定义问题的由来和解决方法
百科的解释
Include防范[编辑]
在C和C++编程语言中,#include防范,有时被称作宏防范,用于处理#include
指令时,可避免重复引入的问题。在标头档加入#include防范是一种让档案等幂的方法。
目录
[隐藏]
- 1重复引入
- 2使用#include防范
- 3困难
- 4外部链接
重复引入[编辑]
以下的C语言程式展示了缺少#include防范时会出现的问题:
- 档案“grandfather.h”
struct foo {int member;
};
- 档案“father.h”
#include "grandfather.h"
- 档案“child.c”
#include "grandfather.h"
#include "father.h"
此处child.c间接引入了两份grandfather.h标头档中的内容。明显可以看出,foo
结构被定义两次,因此会造成编译错误。
使用#include防范[编辑]
- 档案“grandfather.h”
#ifndef H_GRANDFATHER
#define H_GRANDFATHERstruct foo {int member;
};#endif
- 档案“father.h”
#include "grandfather.h"
- 档案“child.c”
#include "grandfather.h"
#include "father.h"
此处grandfather.h第一次被引入时会定义宏H_GRANDFATHER。当father.h再次引入grandfather.h时,#ifndef
测试失败,编译器会直接跳到#endif
的部分,也避免了第二次定义foo
结构。程式也就能够正常编译。
困难[编辑]
为了让#include防范正确运作,每个防范都必须检验并且有条件地设定不同的前置处理宏。因此,使用了#include防范的方案必须制订一致性的命名方法,并确定这个方法不会和其他的标头档或任何可见的全域变数冲突。
为了解决这个问题,许多C和C++程式开发工具提供非标准的指令#pragma once
。在标头档中加入这个指令,能够保证这个档案只会被引入一次。不过这个方法会被潜在性显著的困难阻挠,无论#include
指令是否在不同的地方,但实际上起源于相同的开头(举例,请参考符号连结)。同样的,因为#pragma once
不是一个标准的指令,它的语意在不同的程式开发工具中也许会有微妙的不同。
转载1
转自:关于C语言重复定义的问题-uboot_百度知道
http://zhidao.baidu.com/link?url=CwTM4pmvNHRJRM1Uyi-7clN_Q0v8LAFvBtKmvPVmh9LyezKMZtHws71c_J2KLva2OuZLoSxS1RoCyKTKo1SEaK
关于C语言重复定义的问题-uboot
小弟有一事不明,在uboot源码目录下common/里面有很多命令文件,他们几乎都包含了#include <common.h>文件,而common.h开头用了预编译指令
#ifndef __COMMON_H_
#define __COMMON_H_ 1
变量定义声明
。。。。。。
#endif
问题来了,如果第一个.c文件包含了这个.h文件,别的.c文件也要用到里面的定义声明,那第二个.c文件应用不了这个.h文件了,因为进入第一个.c后执行了
#define __COMMON_H_ 1,第二.c进入后发现定义了 __COMMON_H_ 这个变量,就不会在包含别的声明了。但第二个.c确实要用到.h中的定义啊?这是怎么回事呢??
提问者采纳
#include 相当于把.h文件的内容原样放到.C文件相应的#include位置,
#define只在定义它的c文件中起作用
多个c文件可以使用#define定义相同名称的宏,
但是,多个C文件定义相同名称的全局变量的话,就会出问题了,全局变量在整个工程中起作用;也就是说:
a.c中定义了全局变量 int memory;
b.c中就不能定义全局变量 int memory;
同样,你下面的做法是不行的
---------------------------------
//ss.h
#ifndef comand
#define comand 1 int memory;
#endif
--------------------------------
一般来讲,.h文件中只能声明变量,而不要定义变量,如果多个c文件公用一个变量的话,可以在其中一个c文件中定义该变量int memory;,并在头文件中使用extern int memory;声明该变量。----------------------------------------------------------------------------------------------
#ifndef __COMMON_H_
#define __COMMON_H_ 1
这样写只是为了避免同一个c文件中多次引用同一个头文件,
假设有个a.h文件中,#include了common.h
如果c文件同时#include "a.h" 和<common.h>的话,
#ifndef __COMMON_H_
#define __COMMON_H_ 1
就会起作用了
#ifndef comand
#define comand 1
#define memory 19
#endif
那#define memory 19属于定义还是声明,定义和声明到底应该怎么区分呢??谢谢了
这是宏定义,和普通变量定义是不同的。宏定义不需要声明,只在一个c文件中起作用
一般来讲,普通变量定义一般为数据类型+变量名,例如 int a;
变量一般不需要声明,如果多个c文件想用一个变量的话,可以在其中一个c文件中定义该变量,并在头文件中声明该变量。声明形式为 extern 数据类型+变量名,例如extern int a.
转载2
http://blog.csdn.net/sdustliyang/article/details/6592156
头文件中一般只包含声明,不包含变量的定义,如果没办法必须在头文件中包含定义的话,多次引用该头文件时,常遇到函数或者变量被重复定义的错误,比喻file1.h中定义了int a;file2.h中也定义了 int a;此时在file.c中既包含file1.h也包含file2.h,在预编译是,file1.h与file2.h都会在file.c中展开,就相当于file.c中定义了两次int a;此时会报错redefinition。
如何解决这个问题呢,当工程较复杂时,我们不可能每个文件去找,此时就可以运用宏开关来解决这个问题。file1.h跟file2.h在定义int a的时候,都用
- #ifndef INT_A
- #define INT_A
- int a;
- #endif
这样,在第一次定义a时,由于没有定义宏INT_A,会执行
- #define INT_A
- int a;
此时INT_A宏开关已经打开,以后不会再重复的定义a了。
转载3
http://linux.chinaunix.net/techdoc/system/2006/04/03/930247.shtml
头文件里不要定义变量,采用 extern 声明你的变量和函数。如:
#define HASLABEL 1
#define ISFIELD 0
extern UInt cursor;
//在其他文件里定义
extern Boolean StrIsNum( CharPtr str );
//在其他文件里定义
把函数声明(不是定义)放在公用头文件里不会有什么问题。
而全局变量确实不宜放在header里面定义,如果被多于一个的.c(cpp)引用,就会出现multiple definition。
可以在一个.c里面定义,其它要用的.c前面extern
但如果全局变量太多,也有一个办法可以放在头文件里:
例如有三个.c文件:aaa.c, bbb.c和ccc.c
在all.h里:
#ifndef _defined_here_
#define EXT extern
#else
#define EXT
#endif
EXT int aaa;
EXT float bbb;
...
然后在其中一个.c里加一句
#define _defined_here_
就可以了
另外注意,如:yyy.h yyy.c,在yyy.h中对函数的声明默认就是extern的。
加不加上extern,都无所谓,但是yyy.h定义了的变量,如果这个yyy.h被多个.c调用就会出现重复定义,所以变量放yyy.c中定义,在yyy.h中用extern int xxx外部声明就可以了。还有就是yyy.h中定义的函数同时把函数体也实现了,如:void setB(int a){b=a;},当被多个.c文件引用时也会出现重复定义的错误。。
今天就遇到这个问题,郁闷了半天,终于搞定了,以前都用c++写程序,没大多涉及到函数,全局变量的调用,没注意过这种问题。这些天用c写的代码多了,居然出了一大堆问题,习惯了OO编程,还真不习惯c程序,老觉得不好用。
---下面是在网上搜到的谈到头文件定义问题的一些东西---------------------
例如:
我在程序中建立一个globle.h文件,代码如下:
#ifndef _GLOBLE_H
#define _GLOBLE_H
int a;
int b;
int c;
#endif
有多个.cpp文件引用他,编译的时候说变量重复定义,可是我已经加入了#ifndef这样的语句.
解决方法1:
改成:
#ifndef _GLOBLE_H
#define _GLOBLE_H
extern int a;
extern int b;
extern int c;
#endif
并在其中的一个cpp文件里加上
int a;
int b;
int c;
解决方法2:
/*
* FILENAME: Global.h
* PURPOSE : Global Variabels.
* global 定义前缀使用说明:
* 很多程序将所有的全局变量放在一个文件中定义,然后在另一个头文件中进行
* 声明(加extern修饰). 如var_main.h定义变量,var.h声明变量,这种方法在有
* 大量变量的情况下,可能会造成两个文件不一致,从而引起潜在的问题.
*
* 采用global预编译指令,只要在main.c文件包含其他的头文件之前加入
* #define _MAIN_DEFINE_
* #include "global.h"
* #include "otherfile.h" ,
* 那么编译器将在这个文件中定义变量,在其他文件中只作声明,不会重复定义.
*/
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
#ifdef _MAIN_DEFINE_
#define global
#else
#define global extern
#endif // _MAIN_DEFINE_
// 全局类型 /
typedef enum
{
E_SUCC = 0,
E_COMM_FAIL = 1,
} ERESULT;
// 全局变量 /
需要初始化的全局变量
#ifdef _MAIN_DEFINE_
// global int g_nInit = 99;
#else // just extern
// global int g_nInit ;
#endif // _MAIN_DEFINE_
不需要初始化的全局变量
global long g_lTrace;
// 全局函数 /
void g_fun(void);
#endif // _GLOBAL_H_
当然,如果项目比较大的话,应该把函数申明和类型、结构的定义分别放到其他文件中,再在global.h中引
入,如:
#include "func.h"
#include "macro.h"
#include "struct.h"
转载4
http://www.oschina.net/question/583160_63011
c语言重复定义。。。。
我在头文件(.h)中定义声明了一个变量
int Recusion = 0;/*0,1*/
共有6个答案
【1】
- 先有预处理程序 把include分别包含进 a.c 和 b.c文件中(h文件就没用/丢弃了)
其实这里#ifdef根本没被使用(利用)/没有重复包含嘛 :) - 由编译器和汇编器分别单独 编译+汇编 a.c b.c文件生成a.o 和b.o 到这里没有任何问题.(这里分两步:编译/汇编,我暂时分不出这两步,在这个问题中不是很重要)
- 由连接器 ld 链接 a.o 和b.o 这里发现了重复定义的r变量.
【3】
--- 共有 1 条评论 ---
yandong头文件里面难道不可以放全局变量? (4年前) 回复
--- 共有 1 条评论 ---
yandong嗯嗯,放在.h里面,再使用预处理,使其只包含一次,也不可以啊
#ifndef _INCLUDE_NTREG_H
#define _INCLUDE_NTREG_H
只能保证在一个源文件中不会重复多次引用。
你现在是在两个cpp文件中,而且这两个文件要链接成一个可执行文件,就会有两处定义。
最佳实践是头文件不能有变量的定义,可以有声明。
--- 共有 1 条评论 ---
yandong嗯嗯,理解了
C/C++重复定义问题的由来和解决方法相关推荐
- 苹果cms重复采集重名视频解决方法
1,采集前首先设置一下采集参数,避免采集重复.程序后台->系统->采集参数配置 入库重复规则:勾选"分类""和标题"(意思同一个视频名称,同一分类的 ...
- Android学习笔记-recreate()方法导致fragment重复新建的问题,解决方法
Android学习笔记-recreate()方法导致fragment重复新建的问题,解决方法 今天修改一个比较奇怪的bug: 在操作一个事件的时候,使用eventbus来监听事件,断点发现有时候是会执 ...
- thunderbird(雷鸟)企业邮件每次启动重复收到同一份邮件解决方法
今天同事说用360卫士了一下***,删除了一个文件后,再次打开thunderbird企业邮件的时候每次启动获取新的信息的时候,都是重复收到同一份邮件解决方法.或者那几份邮件. ...
- word表格重复标题行失效的解决方法
有时候点了"重复标题行",第二页却没有出现标题的重复,这时选中整个表格,然后单击鼠标右键"表格属性",将文字环绕改为"无"基本就可以解决该问 ...
- jquery事件重复绑定的几种解决方法 (二)
防止事件重复绑定共有4种方法: bind().unbind()方法 live().die()方法 off().on()方法 one()方法 一.bind().unbind()方法 bind();绑定事 ...
- SVG公众号排版『大尺寸背景图重复安卓不显示』解决方法
今天懂点君给大家分享一个兼容问题,大尺寸背景图平铺/重复在安卓微信上不能正常显示,也就是背景图显示不出来. 一开始我是猜测跟平铺/重复没有关系,是图片尺寸太大导致背景图不显示,具体咱们来看如下案例. ...
- 宝塔同时安装苹果cms海洋cms_★苹果cms常见问题有哪些?100个常见问题的解决方法...
苹果cms是搭建视频网站不错的免费cms系统,再好的系统也会遇到使用方面上的问题,我的主题网在日常中汇总了100多个常见问题来给大家分享交流,后期还会不定期更新遇到的新问题来交流.如果你也是苹果cms ...
- 计算机无法正常更新,无法完成更新正在撤销更改请不要关闭你的计算机的解决方法...
在使用电脑的时候有不少用户遇到这样一个情况,就是电脑开机或者重启之后,会出现蓝屏界面,并显示无法完成更新正在撤销更改请不要关闭你的计算机,很多win7系统和win10系统用户都遇到过,经过分析是不兼容 ...
- 苹果cms常见100个问题及解决方法
苹果cms是搭建视频网站不错的免费cms系统,再好的系统也会遇到使用方面上的问题,我在日常中汇总了100多个常见问题来给大家分享交流,后期还会不定期更新遇到的新问题来交流.如果你也是苹果cms爱好者, ...
最新文章
- 来字节才发现,31岁程序员已经是大团队里最老的了!才发现自己从未真的努力,虽然每天加班到十二点,但只怀着赶紧干完的抱怨!...
- java 开源记账_生鲜配送系统ERP(JAVA开源版)-水产记账ipad
- python中List的sort方法(或者sorted内建函数)的用法
- js实现网页防止被iframe框架嵌套及几种location.href的区别
- Python使用os.listdir()函数来得目录内容的介绍
- LeetCode 381. O(1) 时间插入、删除和获取随机元素 - 允许重复(vector + 哈希)
- 【Java】用for循环实现1+2+3......+100 =
- window10 安装python
- 开发效率不高?强烈推荐这十款精选IDEA插件
- python可以在windows运行吗_在Windows中,如何运行这个python脚本呢?
- PO、VO、BO、DTO、POJO、DAO之间的关系
- 科研 | 中英文期刊分区介绍及查询方法
- html 跑步比赛小游戏,趣味跑步比赛游戏
- 51单片机智能温控风扇
- 小福利,教大家用excel函数实现切片器的功能
- Material Design系列之BottomNavigationView详解
- 获取壁纸网站第一页至第n页的壁纸
- selenium三种等待时间之强制等待
- 偏微分方程的类型及求解(二)(备份草稿)
- 力扣题:977. 有序数组的平方
热门文章
- 微信模板信息群发实现
- NYOJ 416 氢气球
- Taro 框架入门教学视频
- python word处理_python word文件处理
- 笔记本电池的那些事儿
- ssm+jsp计算机毕业设计固定资产管理系统f1e21(程序+lw+源码+远程部署).
- 讯飞语音输入简单使用
- Ubuntu14.04(indigo)实现RGBDSLAMv2(数据集和实时Kinect)
- mfc 对话框 全屏_Web开发人员阅读列表:全屏对话框Web存储和语音API
- 量化大师克里夫·阿斯内斯和他背后的AQR资本