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__)

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

总结

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容

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