宏定义
宏定义是C++编程中一种很常见的语法,有很多使用场景,例如
-
定义一个通用的常量
-
定义一个宏函数
-
实现条件编译
-
其他
第一种使用场景应该是最多的,一般格式如下:
#define PRICE 20
即定义了一个名为PRICE的宏,其值为20。需要注意的是,宏定义本身对C++编译器并不可见,它只是一条 预处理 指令,在预处理阶段,代码中多有的PRICE都会被替换成20。所以在一些编程书籍中,是不提倡使用宏定义来定义变量的,因为在编译出错时,报错信息不方便在代码中定位(上例中如果出错,可能不会报任何与PRICE相关的信息,而是20相关的信息)。
第二种定义宏函数,也是很常见的一种用法,该方法一般用于一些比较简单的函数定义,如求平方函数:
#define SQR(X) ((X)*(X))
这种定义函数的风险比较大,使用时需要谨慎,建议网上搜一下相关的坑,根据自己实际的使用需求来规避风险。同时需要注意的是,宏函数并不是真正意义的函数,它只是一个语句替换,使用时并没有所谓函数调用与返回值等操作,原理和第一种用法相同。
第三种用法是我个人认为在编程中比较有意思的点,先给出一个大家很常见的例子:
//file name: a.h
#ifndef _MY_HEADER_FILE_H_
#define _MY_HEADER_FILE_H_
class Student
{
public:
//...
private:
//...
}
#endif
上述这种处理方式在C++项目中很常见,是一种避免头文件重复引用的方式,假设a.cpp文件包含了上述头文件,那么在编译时,由于没有预定义 _MY_HEADER_FILE_H_,预处理时就会定义出该宏,同时引入该文件中的类定义内容,后续如果其他文件再次重复包含了该头文件,则由于已经定义了该宏,头文件内容就不会被再次包含一遍;
与该应用类似的一种用法是导出类的预处理:
#ifdef MY_FUNC_EXPORT
#define EXPORT_OWNER __declspec(dllexport)
#else
#define EXPORT_OWNER __declspec(dllimport)
#endif
class EXPORT_OWNER MyStudent
{
public:
//...
private:
//....
}
上述例子中,通过宏定义对 EXPORT_OWNER 进行了条件处理,不同条件下,该类分别为导出类和导入类,对于项目自身,在编译时一般生成静态库或动态库文件,类需要编译为导出类,那么只需要预先定义一个 MY_FUNC_EXPORT 宏即可。在调用该类的文件中,包含该头文件时,需要其为导入类,则不定义 MY_FUNC_EXPORT 就行了。
其他还有很多灵活的用法。
注:
对宏定义而言,由于其在预处理阶段会被执行替换操作,因此它一般没法使用命名空间来进行调用。如:
namespace JIUJIU
{
#define NUM1 1000
#define NUM2 2000
}
那么在代码中如果首先加入“using namespace JIUJIU”,然后使用宏定义NUM1和NUM2都是没有问题的,但是直接使用JIUJIU::NUM1或者JIUJIU::NUM2是会报错的,因为两种方法的NUM1和NUM2都会被替换成数字,但是第二种方法引用时相当于是JIUJIU::1000和JIUJIU::2000,而在JIUJIU这个命名空间内,并没有定义1000和2000,所以会报错。
参考:
https://blog.csdn.net/shaonian_wuya/article/details/9883599
https://blog.csdn.net/qq_30815237/article/details/89013148