您的位置:首页 > 编程语言 > C语言/C++

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

2016-02-05 16:40 141 查看

百科的解释


Include防范[编辑]

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



CC++编程语言中,#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_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

#ifndef INT_A

#define INT_A

int a;

#endif

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

[html] view
plain

#define INT_A

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】

先有预处理程序 把include分别包含进 a.c 和 b.c文件中(h文件就没用/丢弃了)

其实这里#ifdef根本没被使用(利用)/没有重复包含嘛 :)
由编译器和汇编器分别单独 编译+汇编 a.c b.c文件生成a.o 和b.o 到这里没有任何问题.(这里分两步:编译/汇编,我暂时分不出这两步,在这个问题中不是很重要)
由连接器 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的。没必要写这个关键字。

好累!!!!!!!!!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: