C/C++ 宏定义

片头图片

宏定义在C语言占有举足轻重的地位。底层框架自不用说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行。使用宏的好处是不言自明,在节省工作量的同时,代码可读性大大增加。


通过本文你将了解到:

  • 宏定义入门
  • 对象宏
  • 函数宏
  • 宏定义变长参数

入门

宏定义简单点说就是查找替换,但是如果如此理解,那么只说对了一半,C中的宏分为两类,对象宏函数宏

对象宏

对象宏一般用来定义一些常数,比如:

#define PI 3.14159

define 关键字表明即将开始一个宏定义,仅接着PI是宏的名字,空格之后的数字是内容。类似这样#define X A的宏是比较简单的,会在编译期间,将X替换为A,这个过程称之为展开。

函数宏

函数宏是用得最多的,函数宏可以节省大量的工作量。

#define MIN(A, B)   A < B ? A : B

int a = MIN(1, 2);
printf("%d", a); => 1

输出正确,可以打包么?
在实际使用中会出问题么,肯定会出问题。

int a = 2 * MIN(3, 4);
//=> int a = 2 * 3 < 4 ? 3 : 4;
//=> int a = 6 < 4 ? 3 : 4;
//=> int a = 4;

现在知道原因了,我因为展开后运算符优先级的问题,乘法先被运算了,修正简单加个括号就行了

#define MIN(A, B) (A < B ? A : B)

仅仅如此么,如果我们执行 MIN(3, 4 < 5 ? 4 : 5) 发现结果为4,展开宏后发现,展开式时链接符号和被展开式中的运算符号优先级相同,导致计算顺序发生变化。所以还得再严格点。

#define MIN(A, B) ((A) < (B) ? (A) : (B))

由上可以知道,函数宏可以简单的将公式展开,这样能节省工作量么,如果仅仅如此,当然不行,不过如果运用好#与##符号就能节省大量的工作。

#与##的使用

# 会将宏参数转换为一个字符串,简单理解就是出现在宏定义中的#是把跟在后面的参数转换长一个字符串

#define ERROR_LOG(msg) printf("error:#msg\n")
ERROR_LOG("add") => printf("error:"add"")

## 是一种分割链接方式,它的作用是先分隔,然后进行强制连接

#define TYPE(type, name) type name##_##type##_type
TYPE(int, a) => int a_int_type

如何节省工作量呢

比如有个数据结构体,对于结构体中的每一种数据都一个操作接口,常规实现方式是每个接口都实现一次,这样随着数据项的增加,工作量会直线增加,利用函数宏可以完美解决这个问题。

typede struct
{
    int nData1;
    int nData2;
    int nData3;
    ...
}TData;

#define DEFADDDATA(name, type) \
void Op##_##name(TData a,type data) \
{ \
    a.n##name += data;      \
}   

DEFADDDATA(Data1, int) 展开后为
void Op_Data1(TData a, int data)
{
    a.nData1 += data;
}   

按照上面所述,每增加一个数据项,只需要一次函数宏语句就可以解决,节省大量工作量。

函数宏的变长参数

宏可以像函数一样,带可变参数。语法如下:

#define debug(format, ...)  printf(format, __VA_ARGS__)
debug("A message") => printf("A message",)

展开还有问题,因为字符串后面没有逗号
解决方法:

#define debug(format, ...) printf(format, ##__VA_ARGS__)

这里,如果可变参数被忽略或为空,##操作将使预处理器去除掉它前面的那个逗号。

总结

宏定义是一把双刃剑,用好了节省大量工作量,并使代码结构清晰,如果不好,跳坑不断,代码结构混乱。
人生是在不断跳坑,填坑的循环中成长。加油!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 宏定义在C系开发中可以说占有举足轻重的作用。底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可...
    你好自己阅读 4,638评论 0 5
  • http://www.open-open.com/lib/view/open1390651437117.html ...
    Xtuphe阅读 5,028评论 0 10
  • 目录 一.预处理的工作方式... 3 1.1.预处理的功能... 3 1.2预处理的工作方式... 3 二.预处理...
    朱森阅读 5,244评论 0 2
  • C中的预编译宏定义 2009-02-10 作者: infobillows 来源:网络 在将一个C源程序转换为可执行...
    白水灬煮一切阅读 5,544评论 0 5
  • 昨晚大宝依然不听话,回家给她买了爱吃的蛋糕,吃完晚饭非要下去遛狗,爷爷说今晚别下去啦,复习功课明天考试,不行就下去...
    平凡精灵阅读 1,917评论 0 0