全局变更使用及编译
最近在弄自已的一个库文件,里面有一个函数用到几个全局变量。
编译时,老是放重定义的错误,调试花了我不了时间。
这是很基础的问题,自己没有重视。回到最初的起点,重新理解一下基础的问题。
一般来说,声明放在.h头文件里面,而定义放在cpp文件里。
有必要弄清楚声明和定义间的区别:
变量的声明就是告诉编译器有这么一个变量,声明是不分配存储空间。如externint x。说明 x在另外一个地方有定义,这里声明使用。
而定义要给这个变量分配存储空间的。如int i =0;这时编译器要给变量分配地址空间的。
一般地:
在使用全局变量时一般将全局变量的定义放在.cpp文件中,全局变量的声明放在.h文件中,若将全局变量的定义放在一个.h文件中容易出现重复定义的情况,具体使用方法如下:
1、在主函数所在的C文件里定义变量(可以初始化,也可不初始化),然后在H文件中,用extern声明,(注意:不能初始化了)。其他需要用到这个变量的C文件,在程序之前include对应H文件就OK.
2、在特定的一个C文件里定义变量(可以初始化,也可不初始化),然户,在H文件中,用extern声明,(注意:不能初始化了)。其他需要用到这个变量的C文件,在程序之前include对应H文件就OK
多次强调不要初始化,因为初始化是要分配内存。这就不是声明。
全局变量是可以多次声明的,但定义只有一次
如在test1.h中:
externint i;
在test2.h:
externint i;
在test.cpp中:
#include"test1.h"
#include"test2.h"
inti=0;
intmain(){
printf("i:%d\n",i);
}
这样使用是没有问题的。
其实编译器是要记你声明和定义过的变量,只有声明或定义过的变量才能使用。
编译器是先在同一个编译单元里编译生成中间文件的,编译器会检查每一个变量。
testA.cpp
int i=0;
在testB.c里
intmain(){
printf("i:%d\n",i);
}
gcc -otestA.o testA.c没有问题
gcc -otestB.o testB.c就会报错。因为找不到i变量。这是因为编译器的还未进行全局的查找,只是在同一个文件中进行检查变量。
这时需使用extern int i;声明来显示告诉编译器,在另外一个文件(编译单元有这么一个变量。)这样,编译器就可以放行。单元编译没有问题。
另一个情况:
testA.c文件中:
int i=0;
testB.c:文件中:
intmain(){
printf("i:%d\n",i);
}
gcc -otestA.o testA.c没有问题
gcc -otestB.o testB.c 没有问题。
再进行链接生成执行文件:
Gcc –o testtestA.o testB.o链接时就会报错,因为变量i重复定义了。变量只有定义一次。
解决这个问题的办法是在testA.h中声明I变量。在testA中,定义这个i变量。而在testA中include“testA.h”头文件,就可以使用了i变量。
注意,条件编译并不能解决这个问题:
如代码:test1.h
#ifndef __A__H__
#define __A__H__
int i =0;
void myprint();
#endif
test1.c文件:
#include <stdio.h>
#include "test1.h"
void myprint(){
printf("%d\n",i);
printf("hello world\n");
}
在main.c中
#include <stdio.h>
#include "test1.h"
int main(){
myprint();
}
编译语句:
gcc -o test1.o -c test.c 没有问题。
gcc -o test main.c test1.o 就会重复定义的错误。
ld: 0711-224 WARNING: Duplicate symbol: i
ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information.
上面的文件关系是这样的:
int i
/ \
test1.o main.o
\ /
test
通过在同一个文件编译生成test1.o , 同样main.o也是在同一个文件中编译生成的。之间都有全局变量 i.
通过链接阶段就会发现有重复的变量。解决办法上面已经说过了。
虽然有条件编译条件,但编译条件并不能解决这个问题的。
如果文件的关系是这样:
A
/ \
C D
\ /
B
上面的文件有关系,C中包含A,D中包含A。 B中要包括C和D,这样条件编译就可把在预处理阶段去掉重复包含文件A。