上个星期回学校的时候,刚好碰到一个学弟在写程序,并且刚好碰到一个总编不过去的问题,我看了看,正好是个头文件重复包含问题,问题描述如下:
他在程序中建立了一个global.h的文件,代码如下:
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
int a;
int b;
int c;
然后在其他文件代码中,有多个.cpp文件引用他,编译的时候编译器报变量重复定义。
其实这是个C语言的基本问题,如果学过编译原理的人就很清除问题在哪里。假设上面的头文件global.h,有三个.cpp文件,1.cpp, 2.cpp, 3.cpp都包含了这个头文件。那么在编译的时候分别生成 1.obj, 2.obj, 3.obj。在这三个obj文件中都包含变量a, b, c。那么在链接的时候你让机器怎么去分别三个a变量,三个b变量,三个c变量,那么就只好给你报个错了。
不过,如果是从事Linux或者以前标准C语言开发的人可能会想,我原来编程就是这么编的,怎么就没有报错。对的,有些编译器是具有这种重定义自动检测的,如Linux下C编程。我目前用的编程环境是Visual studio.net 2003。我写了两个小程序测试了一下,一个是标准C程序,如下:
head1.h
#ifndef _HEADER1_H_
#define _HEADER1_H_
void print_1();
#endif
head2.h
#ifndef _HEADER2_H_
#define _HEADER2_H_
void print_2();
#endif
global.h
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
int g_test;
#endif
head1.c
void print_1()
{
g_test=1;
printf("%d\n",g_test);
}
head2.c
void print_2()
{
g_test=2;
printf("%d\n",g_test);
}
main.c
void main()
{
print_1();
print_2();
}
经过测试,这种方式是对的。
然后,我写了段c++代码,程序代码和上面的一模一样,就是.c文件变成了.cpp文件。结果就报重定义的错误。
由此可见,这个问题是C++新标准。而上述标准C能够编译过,说明这种对重定义的支持是依据编译器的,但是对于编译器来说,不是必须的。所以程序员写程序最好不要用上述代码写,现在一般程序员对这个问题流行的写法是如下:
#ifndef _GLOBLE_H
#define _GLOBLE_H
extern int a;
extern int b;
extern int c;
#endif
然后在其他的某个.cpp文件中定义
int a;
int b;
int c;
但是这种写法在具有大量的变量时候,容易造成声明的头文件和变量定义的cpp文件中变量的不一致。
下面是我给出一个的解决方法。
定义一个宏,如:MAIN, 在global.h中,加入如下代码:
#ifdef MAIN
#define EXTERN //定义变量
#else
#define EXTERN extern //声明变量
#endif
EXTERN int a;
EXTERN int b;
EXTERN int c;
然后在你的1.cpp , 2.cpp , 3.cpp 中,在其中的一个.cpp中
#define MAIN
#include "gloabl.h"
进行定义。这样相当于对gloabl.h中的变量进行定义。
而在其他的cpp中,如需要引用global.h中的变量,则
#include "gloabl.h"
而不需要#define MAIN.或者将#define MAIN定义在#include "gloabl.h"的后面。这样编译的时候就会将gloabl.h中的变量作为声明来看待。
这样即使变量再多,也不会出现头文件和CPP文件中的变量不符。因为所有的变量只需在一个文件中写入。
嘿嘿,完了,不知道有没有说清楚。如果还有疑惑欢迎大家提问交流。
评论