C++老鸟日记019 头文件的多次声明与预处理指示符

微信公众号: 星点课堂

新浪微博:女儿叫老白

网易云课堂:女儿叫老白

网易云课堂免费课程:《C++跨平台开发中的编译错误》

----------------------------------------------------------------------------

(4.7.2)

引言:

----------------------------------------------------------------------------

       我们在编程的时候,经常见到头文件的开头有一个#ifdef的宏定义判断,它是用来干啥的呢?有什么需要注意的呢?今天我们就来讨论一下这个问题。

 

正文:

----------------------------------------------------------------------------

       C++语言允许重声明函数,但不允许重声明结构,因为如果出现两个同名的结构,编译器不知道该用哪一个。而我们的结构体一般放在头文件中,而且头文件很可能被多个cpp包含,当编译某个编译单元(cpp)时,非常有可能发生这种情况:对某一个头文件多次包含(因为不知道再什么地方可能包含该头文件)。比如:

       // a.cpp

       #include “b.h”

       #include “c.h”

 

       // c.h

       #include “b.h”

 

       上述代码中,a.cpp包含了b.h和c.h,而c.h又包含了b.h,因此,在编译a.cpp时将会包含两次b.h。而这将导致头文件重入问题,也就是头文件中的结构体或者类会被编译器多次检测到,进而导致编译错误。

       预防的方法就是使用预处理指示符:#ifdef, #ifndef, #define #endif等。

       用法如下:

       // myclass.h

       #ifndef  __MYCLASS_H__

       #define __MYCLASS_H__

       …… // 代码区

       #endif // __MYCLASS_H__

      

       上述代码是头文件的标准写法。开头先用#ifndef判断是否已经定义了__MYCLASS_H__这个宏,如果没有定义则定义这个宏,如果已经定义了,则该头文件中的所有内容都被编译器跳过。与#ifndef配套使用的是末尾的#endif,它用来告诉编译器#ifndef的判断结束。防止#ifndef的作用域未关闭而影响到后续文件的编译。

       这里牵连出#define预处理指示符的用法。一般我们用它来定义常量,比如:

       #define PI      3.14

     这里我们用来定义一个标识符__MYCLASS_H__,目的是让编译器知道有这样一个符号存在。下次编译器再次进入这个头文件时,因为在此之前编译器已经建立过这个符号了,因此这次就会识别出该符号并跳过整个#ifndef与#endif之间的代码段。

       说到#define常量的语法,实际上我们不推荐这种方法。而推荐使用static定义文件局部变量的方法来定义常量。方法如下:

       // const.h

       static double s_dDetectDistince = 3.f;

       static double s_Pi  = 3.1415926535897932f;

 

       原因有两个:

       1.  编译器无法识别宏定义中的语法错误,如果真的存在错误,那么只能到运行期才能发现。这不是我们希望看到的。

       2. 如果您的产品使用命名空间,那么它是无法保护宏定义的,但是static变量和枚举是受命名空间保护的。

       因此,建议您尽量使用static变量来定义常量。

      

结语:

----------------------------------------------------------------------------

       #ifndef预处理指示符可以有效防止头文件的多次声明和重入。使用它是头文件的标准编程方式。希望大家都使用公司强制或推荐的编码规范进行编程,这样可以减少很多不必要的麻烦。

猜你喜欢

转载自blog.csdn.net/baizy77/article/details/82670023