C/C++重复定义问题的由来和解决方法

百科的解释

Include防范[编辑]

维基百科,自由的百科全书

CC++编程语言中,#include防范,有时被称作宏防范,用于处理#include 指令时,可避免重复引入的问题。在标头档加入#include防范是一种让档案等幂的方法。

重复引入[编辑]

以下的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_GRANDFATHER
 
struct 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

转自:如何解决“重复定义” - SdustLiYang的专栏 - 博客频道 - CSDN.NET
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的时候,都用

[html]  view plain
  1. #ifndef  INT_A  
  2. #define INT_A  
  3. int a;  
  4. #endif  

这样,在第一次定义a时,由于没有定义宏INT_A,会执行

[html]  view plain
  1. #define INT_A  
  2. int a;  

此时INT_A宏开关已经打开,以后不会再重复的定义a了。

转载3

转自:头文件定义的问题-解决重复定义 - 技术文档 - 系统管理 Linux时代 - 开源、自由、共享 - 中国最大的Linux技术社区
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

转自;c语言重复定义 multiple definition of `Recusion' - 开源中国社区
http://www.oschina.net/question/583160_63011

c语言重复定义。。。。

我在头文件(.h)中定义声明了一个变量

int Recusion = 0;/*0,1*/

然后在两个.cpp文件中使用
a.cpp
--------------------------
Recusion = 1;

b.cpp
--------------------------
 if(Recusion && ...)
{
}

但是编译却有这个错误,怎么回事?
multiple definition of `Recusion' 
难道是他们都包含头文件,以致于多次定义,可是我的头文件有做处理啊

#ifndef _INCLUDE_NTREG_H
#define _INCLUDE_NTREG_H 1

共有6个答案

【1】
  1. 先有预处理程序 把include分别包含进 a.c 和 b.c文件中(h文件就没用/丢弃了)
    其实这里#ifdef根本没被使用(利用)/没有重复包含嘛 :)
  2. 编译器汇编器分别单独 编译+汇编 a.c b.c文件生成a.o 和b.o 到这里没有任何问题.(这里分两步:编译/汇编,我暂时分不出这两步,在这个问题中不是很重要)
  3. 连接器 ld 链接 a.o 和b.o 这里发现了重复定义的r变量.
以我现有的知识是这样的过程.参照编译原理之类的知识.
extern(?)关键字可以解决这个问题.
【2】
参考这个http://general.blog.51cto.com/927298/235077
把变量放到a.c中,在.h中加上extern就可以了,但是为什么把变量放到.h中,在.c中加extern为什么不行
【3】
你头文件处理理解错了
--- 共有 1 条评论 ---
yandong头文件里面难道不可以放全局变量? (4年前)   回复
【5】
全局变量放.c里 
--- 共有 1 条评论 ---
yandong嗯嗯,放在.h里面,再使用预处理,使其只包含一次,也不可以啊
【6】
你确实是定义了两次
#ifndef _INCLUDE_NTREG_H
#define _INCLUDE_NTREG_H 
只能保证在一个源文件中不会重复多次引用。
你现在是在两个cpp文件中,而且这两个文件要链接成一个可执行文件,就会有两处定义。
最佳实践是头文件不能有变量的定义,可以有声明。
--- 共有 1 条评论 ---
yandong嗯嗯,理解了
【7】
头文件中改为 int  Recusion; 就好了。C语言中全局变量默认是extern的。没必要写这个关键字。


好累!!!!!!!!!!!!
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值