C++预处理命令#define宏(macro)展开的若干用法
来源:互联网 发布:淘宝美国末日ps3 编辑:程序博客网 时间:2024/05/20 18:46
然而 #define宏展开的用法远不止这一点,它还有其他更多让人意想不到的方式,好好利用,可以提升你的代码质量。笔者在此作一个小小的总结,以便大家查阅。
#define指令一共有两种语法定义
Syntax
#define identifier token-stringopt
#define identifier[(identifieropt,...,identifieropt )]token-stringopt
第一种是形如#define MAX 100之类不带参数的定义,而第二种就是笔者今天要重点提及的形式,带参数形式宏展开。
#define WIDTH 80#define LENGTH ( WIDTH + 10 ) //不带参数宏定义
话不多说,咱看例子Example1:
#include <iostream>#define Error(n) std::cout<<"Error "#n<<std::endl;//宏展开 #define Joint(a,b,c) a##b##c //连接字符串a,b,c int main(){Error(123);unsigned int Link = Joint(12,06,3);std::cout << link << std::endl; return 0;}
运行结果:
Error 123
12063
这种用法是把一个类似于函数形式的表达式宏展开,Error(n) 在编译时会用std::cout<<"Error "#n<<std::endl语句替代,这句话的作用就是输出字符串"Error",接着用"#"连接n,n的值需要在程序编写时指定,而不能用类似于函数的形式接受"用户"的赋值。
如果在Error(123);这句之前加上
int test;
std::cin >> macroT;
Error(macroT);
这里不会发生奇迹。你输入一个123或者任何其他的数字,它运行结果只会是这样
Error macroT
而不是Error 123(或其他数字)
给你5秒钟想想为什么?
。。。
有些人会说,这句宏展开的样子长得实在太像函数了,就像双胞胎一样。
然而它们的本质却确完全不一样。一个是编译时执行(#define Error(n)),而一个是运行时执行(void Error(n))。
仔细想一下,编译是在运行之前执行的,而std::cin>>macroT是在运行时才执行的,所以它们是配不到一块去的。至于为什么会输出"test"这样的字符串,
通过解释这句代码
std::cout << "Compile:";
Error(macroT);
结合宏展开
Error(n) std::cout<<"Error "#n<<std::endl;可以推断它Error(macroT)作用实际是
输出字符串"Error"+"macroT",没错,这里的macroT它不是那个整型变量macroT,只是一个字符串型参数,即n,n后面"#"的作用是把字符串n连接到之前的"Error "字符串中。
还不明白?下面这个例子会加深你的理解。
#include <iostream>#define Error(n) std::cout<<"Error "#n<<std::endl;//宏展开 #define Joint(a,b,c) a##b##c //连接a,b,c字符串void ErrorRun(int n){ //函数调用方式 std::cout << "Error " << n << std::endl;}int main(){int macroT;std::cin >> macroT;std::cout << "Compile:";Error(macroT);// macroT只是一个参数,名字跟之前定义的int型变量相同而已,代表的东西不同 // macroT在编译时就进行了连接,先于int型变量。std::cout << "Run: ";ErrorRun(macroT);//通过函数调用才是int型的变量macroT,它是用户在运行程序时指定的unsigned int Link = Joint(12,06,3);std::cout << "Joint: " Link << std::endl; return 0;}
输入123
运行结果:
Compile:Error macroT
Run: Error 123
Joint: 12063
明白了吧。我这么笨瓜的人都懂了。这个弄懂了下面的Joint(a,b,c)就稍好说了。首先,两条宏指令大体上相同,不过Joint(a,b,c)后面不是一个输出这样的动作型语句了,而是a##b##c。那么##是连接什么类型?int?char?char*?还是什么?假设你不知道,可以经过多次试验证实##只连接int 型。
#define Joint2(a,b,c) a#b#c
char Link2 = Joint2('12','06','3');
std::cout << Link2 << endl; //通不过编译
所以不能想当然地“造句”。
#define Joint(ab,c) a##b##c
unsigned int Link = Joint(12,06,3);
作用:先将Joint(12,06,3);展开为12063,这个数是int型,再将其赋值给Link,,最后输出。
NOTE:宏展开只占编译时间,不占运行时间。函数调用会影响运行时间,需要分配单元,保留现场,值传递,返回。
再举个例子
Example2:
#include <iostream>using namespace std;// Macro to get a random integer with a specified range #define getrandom(min, max) \ ((rand()%(int)(((max) + 1)-(min)))+ (min)) //得到随机数的公式 inline int GetRandom(int min,int max){ //内联地展开 return (rand()%(int)(max+1-min)+min); }int main(){srand((unsigned)time(NULL));//时间种子,每次运行时得到的随机数都不相同cout << "Get Random number through #define:" << endl;//通过宏展开方式得到10个随机数 for(int i = 0; i != 10; ++i){ int tmp = getrandom(2,100); cout << tmp << ' ';}cout << endl;cout << "Get Random number through function:" << endl;//通过函数调用方式得到10个随机数 for(int i = 0; i != 10; ++i){ int temp = GetRandom(2,100); cout << temp << ' ';}cout << endl;return 0;}
这里定义GetRandom(int,int)为内联函数,由于笔者今天重点在宏上,所以对内联函数不作详解(感兴趣的话点击我)。内联函数类似于宏展开,形式像函数,但是它是编译时直接展开的。有一点很奇怪,GetRandom(int,int)可以接收在运行时得到的min和max(这一点宏展开绝对不允许,但内联函数做到了)。如果你知道原因的话请留个言告诉我吧。
int min,max;cin >> min >> max;for(int i = 0; i != 10; ++i){ int temp = GetRandom(min,max); //接收运行时的值,不明白为什么还能正常工作。 cout << temp << ' ';}
注意:在宏展开语句#define getrandom(min, max) \
((rand()%(int)(((max) + 1)-(min)))+ (min)) 中的公式((rand()%(int)(((max) + 1)-(min)))+ (min)) (max)和(min)一定要加上括号,不然易出错。
如:
#define PI 3.1415926
#define DEMO(r) PI * r * r
...
area =DEMO(3);
显然这样是没有什么问题,但是,如果是area = DEMO(a+b);(假定a,b已经在编程时赋值)呢?宏展开是PI * a + b * a + b,这与我们的意愿不符,所以,应该设计成以下方式
#defien DEMO(r) PI * ( r ) * ( r )
这样会展开为PI * ( a + b) * (a + b),不容易出错。养成良好的习惯非常重要。
函数可以用过引用的方式返回多个值:
如int DEMO(int a,int &b,int &c){
...
return a;
}
可以返回a,b,c三个值。
宏展开也可以返回多个值:
Example3:
#include <iostream>#include <iomanip> //用于保留小数点位数 using namespace std;#define PI 3.1415926#define A 100#define B 200#define RADIUS 50#define AREA(LINE,RECTANGLE,TRIANGLE,CIRCLE)\ LINE = 0; RECTANGLE = A * B;\ TRIANGLE = 0.5 * RECTANGLE; CIRCLE = PI * RADIUS * RADIUS;//RECTANGLE 先于TRIANGLE正确 #define CIRCLE(R,L,S,V) L = 2 * PI * R; S = PI * R * R; V = 4.0/3.0 * PI * R * R * R;int main(){ float line,rectangle,triangle,circle; AREA(line,rectangle,triangle,circle); cout << line << "\t" << rectangle << "\t" \ << triangle << "\t" << circle << endl; float r,l,s,v; cin >> r; CIRCLE(r,l,s,v); //返回多个值 cout << r << "\t" << l << "\t" << s << "\t" << v << endl; cout.precision(2); cout<<setiosflags(ios::fixed)<<setprecision(2)<<s<<endl; // 保留两位小数 return 0;}
这个程序比较好理解,大家可以自己琢磨一下。关于宏展开的用法就交流到这里吧。相信看完此篇文章,你会对#define指令有一个更深层次的理解。
附录:
可以用#undef命令终止宏定义的作用域。
int main(){...}//#define有效范围截止于此#undeff1(){...}
- C++预处理命令#define宏(macro)展开的若干用法
- C语言中预处理命令#define的用法
- 宏(Macro, define)的一个有趣用法
- 宏的用法(macro in C)
- C/C++预处理指令#define 之##连接符的用法
- C语言中宏(macro)的特殊用法
- 预处理器#ifndef,#define,#endif 的用法
- bat的命令若干用法
- 预处理命令之#define
- C语言中Macro的终极用法
- C语言中宏#define的用法
- C宏#define的一些用法
- C语言之#define用法(宏定义命令)
- C语言之#define用法(宏定义命令)
- c语言define的用法
- 【C++】define的用法注意
- C语言#define的用法
- #define预处理的弊端
- python 的包管理器 easy_install
- 侵占营业款流程
- IPhone之播放系统声音
- 斐波那契数列算法分析
- IPhone之IO操作
- C++预处理命令#define宏(macro)展开的若干用法
- 在Java中byte类型数据在运算的问题
- MX233物理存储空间学习
- Android Codec 集成和 video Overlay
- 怎样使用orapwd新建口令文件
- 静态代码块(static block)
- gSOAP简单使用例子
- 贪婪算法之0/1背包问题+读数据结构算法与应用-C++语言描述
- LINQ to SQL