看到博客里面都不推荐将全局变量定义到.h文件中,表示很困惑,加上一开始就对文件包含关系不是很理解,所以今天通过查找资料和测试力争将问题搞懂。
首先测试#ifndef #define #endif 在头文件编译中到底能够起到什么作用能?1.能够控制整个工程对于该头文件的包含,也就是说对于添加了#ifndef #define #endif
的头文件一个工程只会包含一次该头文件。2.只能控制一个.c文件只包含这个头文件一次。下面我们定义一个testGlobal.h文件和两个包含该.h文件的.cpp文件,testGlobal.cpp和
testGlobal2.cpp内容如下:
testGlobal.h
#ifndef TESTGLOBAL_H
#define TESTGLOBAL_H
int GlobalCount;
#endif
testGlobal.cpp
#include "testGlobal.h"
testGlobal2.cpp
#include "testGlobal.h"
#include <iostream>
void main()
{
std::cout<<GlobalCount<<std::endl;
}
此时编译器会提示,redefined这说明两个C文件中都直接包含了头文件的内容。
接下来我们分析#ifndef #define #endif在防止一个C文件将同一个头文件包含两次的作用。这里重新定义一个文件testGlobal2.h
#ifndef TESTGLOBAL2_H
#define TESTGLOBAL2_H
#include "testGlobal.h"
int GlobalCount2 = 5;
#endif
将testGlobal.h和testGlobal2.h都包含到testGlobal.cpp中,并清除testGlobal2.cpp,此时可以顺利编译。可见#ifndef的声明只对一个.cpp文件而言。
基于上述问题,一般在使用全局变量时,都将全局变量定义到某一个.cpp文件中,在.h文件使用extern从而避免出现重定义的问题。
对于.h文件中的宏定义是有编译器直接替换为常值的,不会编译到.obj文件中,所以不会出现重复定义。同时也可以在.h文件中定义结构体,枚举因为这些都是由
有编译器处理,直接在编译时候替换的,所以也不会报错。
实际上有关全局变量重定义的问题在《深入理解计算机系统》一书中有叙述:链接器在解析全局符号时,会遵循以下原则:
1.不允许有多个强符号
2.强弱符号都有选强
3.多个弱符号,任选其中一个
强符号是指:函数和已初始化的全局变量;成员函数如果定义在类外面,那么是强符号;模板函数的特化版本是强的;
弱符号是指:未初始化的全局变量;成员函数如果定义在类里面,那么是弱符号;模板类中的成员函数无论定义在类内还是类外,都是弱类型;模板函数是弱类型;
实际上强弱符号判断是可能出现问题的。因为编译器实际操作的全局变量可能并不是你希望的,可能造成错误。
如果想在全局变量重复定义就发出警告的话,对于GCC可以添加GCC-warn-common选项。通过我的测试在CCS的c编译器上面,在同一个.c文件中重复定义变量
不会报错编译器是按照强弱符号进行判断的,但是要是在不同文件中定义了相同的变量就会报错。而使用g++编译的C++程序,后缀.cpp上述两种情况都会报错,通不
过编译。
通过以上分析,在定义全局变量不应该定义在.h文件中。