跟我学C++中级篇——基础的宏技巧

一、宏应用

虽然作为一名C++程序员可能宏的应该被限制的太多。但在某些情况下宏还是能起到非常大的作用的。特别是在和一些硬件或底层打交道时,宏的应用也是经常需要的。所以对一些基础的宏的使用经验和技巧还是要掌握的。

二、常见的宏技巧

经常遇到的宏的技巧有以下几种情况:
1、限制性展开
基本上程序员都知道宏的替换展开,如果一不小心就会因为运算符的优先级或者括号处理等原因导致展开后的计算表达式并非自己需要的,结果也可想而知,一定是不正确的。那么如何正确的展开一个宏,其实就是要利用好括号以及do…while。是的,没有错,一个循环。
括号做为限制性展开的一个手段,一般只能在比较简单的情况下比较好控制,这个就不举例了。但在复杂时,一不小心可能就仍然无法达到想要的效果,所以一般是使用do…while(0),看一个简单的例子:

#define myfunc(a, b)  do {      \
  init(a,b);              \
  exec(a,b);               \
} while (0)
//use
if (1)
   myfunc(1,2);

它可以很好的解决在判断语句(如if)后面产生的代码执行问题以及消除一些不必要的编译错误(如多一个;号)。
2、变参宏
变参对学习过模板变参的应该是小菜了,但它也有可爱的一面,看下面的例子:

#define MSG(...) printf(__VA_ARGS__)
or
#define MSG(fmt,...) printf(fmt,##__VA_ARGS__)//##目的是为了处理单个参数时的逗号编译问题

MSG("test: %d \n",100);

3、获取结构体的信息
这种有点类似通过成员反过来获取类或结构体对象的地址,看下面的例子:

//ptr结构体中当前可用成员的指针,type为结构体名字,member为已知成员名字
#include <stddef.h> //C99后可以使用此头文件而省略下面的offsetof定义
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({      \
  const typeof(((type *)0)->member) *__mptr = (ptr);  \
  (type *)((char *)__mptr - offsetof(type, member));  \
})

//应用
struct A{
  int a;
  int b;
};
bool getA(int *p1){
struct A *a_=  container_of(p1,struct A,a);//对比一下上面的说明
return true;
}

内核或硬件嵌入式开发中,类似的宏应该经常看到。

4、#和##
这两个运算符在宏中非常重要,前者负责将转参数转为字符串,后者可以将多个参数连接在一起。前面分析过,看一个简单的例子:

#define MSG(d) printf("a" #d " = %d\n", a##d);

int a1 = 1;
int a2 = 2;
MSG(1);
MSG(2);

大家是不是迅速想到,这种方法可以用于有规律的变量的自动处理,对,就是这样。
上面的技巧是比较常用的一些,推荐给大家。其实用宏展开来自动生成代码也是一项重要的应用,不过,争议也非常大。所以这里就不对其做推荐了。

三、提高的手段

提高对宏使用的最好的方法就是看Linux内核的代码,不过内核中的宏应用很多都和GNU做了一定的绑定,要注意应用的环境。另外一个就是多在实践中使用,由浅入深,从简单到复杂。不过需要注意的是,尽量不要使用复杂的宏技巧,除非特别需要。

四、总结

这里不是强调大量使用宏或者推广宏的应用,而是在应该用的场景下坚定的引入宏。合适的就是最好的,不能因噎废食,更不能搞绝对化。原则上仍然是不建议在开发中广泛而大量的应用宏,用就要用到刀刃上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值