C++ macro(宏)使用小结

Posted dnbc66

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ macro(宏)使用小结相关的知识,希望对你有一定的参考价值。

  谈起C++中的宏,我们第一个想到的应该就是“#define”,它的基本语法长得像这样:

1 #define macroname(para1, para2, para3, ... ,paran) macro-body

  宏的声明和普通的函数声明很像,但是两者之间有本质的区别:C++函数在运行时(runtime)才执行代码段;而宏则是在预编译时期(preprocessor)执行代码段。下面简单介绍一下几个宏的应用。

 

一、考虑下面的代码段:

1 #define PLUS_ONE(x) ((x) + 1)
2 int x=PLUS_ONE(12);
>>>x=((12) + 1)
>>>x=13

  这是最简单的应用,用macro-body替换macroname;和C函数不一样的是,宏是没有返回值的,本身表达式的值将作为返回值传回。

 

二、考虑下面的代码段:

1 #define x 1+2
2 int t=x*3;
3 std::cout<<t<<\n;

  那么输出t的值会是什么呢?答案也许不是你期望中的9,而是7。原因很简单,#define的替换实质上是表达式的替换,将上述代码里的宏展开后将变成这样:

  int t = 1 + 2 * 3;   //t = 7

  这种结果显然不是我们愿意看到的,而且这种错误是很难察觉的,完全没有语法错误和语义错误;不过要解决这个问题也很容易,将表达式括起来就行了:  

1 #define x (1+2)
>>>int t = (1+2)*3=9

  不过这种使用宏的方法是不推荐的,因为容易引起一些不必要且难以察觉的错误。在C++里,我们完全可以这样声明x,也能达到同样的目的:  

1 const int x=3;  //声明常数推荐用const关键字

 

三、Preprocessor预先定义好的值;

__FILE__ :编译的文件的绝对路径;

__LINE__ :当前行号;

__TIME__ :当前时间;

__DATE__ :当前日期。

 

四、C语言中macro的设计初衷之一是关于内联函数。如果我们定义一个求较大值的MAX函数:

1 #define MAX(a,b) ((a)>(b)?(a):(b))
>>>int myInt=MAX(x,y)
>>>int myInt=((x)>(y)?(x):(y))  //上一行调用的宏将直接这样插入到代码段里

  如果我们将MAX写成一个一般的函数,那么我们调用MAX将有以下两个过程:①调用名称为MAX的函数 ②将比较得到的值返回。显然在这两种方案中,macro的方案更较高效,因为它省略的函数调用的开销,直接能得到结果(相当于inline函数的用法,这里不展开讲inline了)。

 

五、字符串操作函数

  看如下macro定义:

1 #define MAX(a,b) ((a)>(b)?(a):(b))

  这里的参数a和b实际上都是以string的方式传递的,例如MAX(10,12)返回的是字符串"12",而不是整型的12。预处理器提供两种方式处理string类型的参数传递。

1、stringizing operator ‘#‘:返回一个C风格的字符串;

1 #define TEST(n) std::cout << #n << " is " << (n) << std::endl
>>>int x= 6;
>>>TEST(x*2);  //std::cout << "x*2" << " is " << (x*2) << std::endl

  最终得到的结果是:x*2 is 12

  那么这种看似tricky的语法有什么用呢?其实,当上述C++代码被翻译成机器码时,所有和变量x相关的概念或者语句都会被“消灭”,因为变量只会存在于C++代码层;而通过stringizing operator,让我们以字符串的形式保存一部分C++源代码变得可能,这可以应用于写一些“自我诊断(纠错)”的函数中,有机会再深入介绍吧!

2、string concatenation operator ‘##‘:顾名思义,字符串连接算子:

1 #define TEST2(type) type ones_##type
>>>TEST2(int);
>>>int ones_type;  //这个宏的功能其实就是声明一个任意类型的,如int的变量,名字叫做ones_type

  这个没感觉有什么特别的用途,trick。

 

以上是关于C++ macro(宏)使用小结的主要内容,如果未能解决你的问题,请参考以下文章

错误注入 异常行为 环境变量或代码动态激活来触发这些异常行为 模拟错误 容错性 正确性 稳定性 宏 本质 macro

macro_rules 是常规宏吗?

Rust 1.7.0的macro宏-语法分析和使用举例

转 freemarker macro(宏)的使用

从父模块导入宏[重复]

在macro_rules中使用另一个宏而不需要生锈的“extern crate”