宏定义学习
【1】宏定义怎么理解?
关于宏定义,把握住本质:仅仅是一种字符替换,而且是在预处理之前就进行。
【2】宏定义可以包括分号吗?
可以,示例代码如下:
1 #include<iostream>
2 using namespace std;
3
4 #define PI 3.14; //宏定义可以包括“;”
5
6 void main()
7 {
8 double r=10,s;
9 s=r*r*PI //注意此处的语法
10 cout<<s<<endl; //314
11 }
【3】宏定义一种新类型如何实现?
示例代码如下:
1 #include<iostream>
2 using namespace std;
3 #define int int *
4 void main()
5 {
6 int a,b;// int *a, b;
7 }
8 //理解此处的微妙:int *a,b; 这条语句同时定义了两个变量。一个指针:int *a; 一个变量:int b;
【4】宏定义一个函数如何实现?
示例代码如下:
1 #include<iostream>
2 using namespace std;
3
4 #define Begin() {int a;a=0;cout<<"a="<<a<<endl;}
5
6 void main()
7 {
8 Begin()
9 }
10 //如果{......}中的代码太多,应该使用宏连接
11 //代码如下所示:
12 #define Begin() { int i;\
13 i=10;\
14 cout<<"i="<<i<<endl;}
【5】宏定义如何取消?
示例代码如下:
1 #include<iostream>
2 using namespace std;
3
4 #define int int *
5
6 void main()
7 {
8 int a, p; // int *a,p;
9 a = &p;
10 #undef int //取消宏定义
11 int b = 10;
12 a = &b;
13 }
【6】对宏定义歧义现象怎么识别?
示例代码如下:
1 #define SUM(x,y) x*y
2 #define SUMM(x,y) ((x)*(y))
3 void main()
4 {
5 int a = 4, b = 5;
6 cout<<SUM(a+2,b+4)<<endl; //18
7 cout<<SUMM(a+2,b+4)<<endl; //54
8 }
求一个数的平方正确的宏定义:
#define S(r) ((r)*(r))
这个宏定义注意事项:
(1)宏名和参数的括号间不能有空格
(2)宏替换只作替换,不做计算,不做表达式的求解
(3)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前执行,不分配内存
(4)宏的哑实结合不存在类型,也没有类型转换
(5)函数只有一个返回值,利用宏则可以设法得到多个值
(6)宏展开使源程序变长,函数调用不会
(7)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存 保留现场 值传递 返回值)
何谓哑实结合?
示例代码及解释如下:
1 #define S(a,b) a*b
2 void main()
3 {
4 int area = 0;
5 area = S(3,2); //第一步:被替换为area = a*b; 第二步:被替换为area = 2*3;
6 //类似于函数调用,有一个哑实结合过程
7 }
【7】下面宏定义特例如何解析?
示例代码如下:
1 #define NAME "zhangyuncong"
2 //#define AB "liu //error!!编译错误
3 //#define 0x abcd //error!!编译错误
4 void main()
5 {
6 cout<<NAME<<endl; //zhangyuncong
7 cout<<"NAME"<<endl; //NAME
8 cout<<"NAMElist"<<endl;//NAMElist
9 //cout<<NAMEList<<endl; //error!!!!编译错误
10 }
也就是说,这种情况下记住:#define 第一位置 第二位置
(1)不替换程序中的字符串内的任何内容
(2)第一位置只能是合法的标识符(可以是关键字)
(3)第二位置如果有字符串,必须把“”配对
(4)只替换与第一位置完全相同的标识符
总之一句话:仅仅只是简单的替换而已,不要在中间计算结果,一定要替换出表达式之后再计算
【8】宏定义的特例有参形式如何解析?
示例代码如下:
1 #define FUN(a) "a"
2 void main()
3 {
4 cout<<FUN(345)<<endl; //a
5 cout<<FUN(a)<<endl; //a
6 cout<<FUN("a")<<endl; //a
7 char *str=FUN(abc);
8 cout<<str<<endl; //a
9 }
通过上例可以看到,如果这样写,不论实参是什么,都不会摆脱被替换为“a”的命运。也许,你会问,那么我要实现FUN(345)被替换为“345”??肿么办呢??
请看下面这个用法
【9】有参宏定义中#的有何作用?
示例代码如下:
1 #define STR(str) #str
2
3 void main()
4 {
5 cout<<STR(abc)<<endl; //abc
6 cout<<STR("abc")<<endl; //"abc"
7 cout<<STR(123)<<endl; //123
8 cout<<STR(my#name)<<endl; //my#name
9 // cout<<STR(()<<endl; //error!!编译错误
10 cout<<STR(.)<<endl; //.
11 // cout<<STR(A,B)<<endl; //error!!编译错误
12 cout<<STR(())<<endl; //()
13 const char * str=STR(liuyong);
14 cout<<str<<endl; //liuyong
15 }
备注:代码编译环境为VS2010 那么相信“#”的作用也一目了然。在此不作赘述。
【10】有参宏定义中##有何作用?
示例代码如下:
1 #define SIGN( x ) INT_##x
2 #define WIDE(str) L##str
3
4 void main()
5 {
6 int SIGN(a);
7 // int INT_a; //error!! redefinition
8 char * WIDE(a);
9 // char *La; //error!! redefinition
10 }
【11】当一个宏自己调用自己时,会发生什么呢?
例如:#define TEST(x) ( x + TEST( x ) )
TEST(1); 会发生什么呢?为了防止无限制递归展开,语法规定:当一个宏遇到自己时,就停止展开。
也就是说,当对TEST(1)进行展开时,展开过程中又发现了一个TEST,那么就将这个TEST当作一个
一般的符号。TEST(1)最终被展开为:1 + TEST(1)。
【12】可以举一个变参宏的例子吗?
示例代码如下:
1 #define LOG( format,... ) printf( format, __VA_ARGS__ )
2
3 void main()
4 {
5 int a = 10;
6 char *str = "abc";
7 LOG("%d,%s",a,str); //10,abc
8 }
【13】当宏作为参数被放进另一个宏体时,将会发生什么?
当一个宏参数被放进宏体时,这个宏参数会首先被全部展开(当然,没有绝对,也有例外)。当展开后的宏参数被放进宏体时,
预处理器对新展开的宏体进行第二次扫描。并继续展开。举例说明:
示例代码如下:
1 #define PARAM(x) x
2 #define ADDPARAM(x) INT_##x
3
4 void main()
5 {
6 int PARAM(ADDPARAM(1));
7 // int INT_1; //error!! 编译错误 重复定义
8 }
因为ADDPARAM(1)是作为PARAM的宏参数,所以先将ADDPARAM(1)展开为INT_1,然后再将INT_1放进PARAM。
也有例外,如果PARAM宏内对宏参数使用了# 或者 ## ,那么宏参数不再被展开。例如:
1 #define PARAM( x ) #x 2 #define ADDPARAM( x ) INT_##x 3 PARAM( ADDPARAM( 1 ) ); 将被展开为"ADDPARAM( 1 )"。
Good Good Study, Day Day Up.
顺序 选择 循环 总结