宏定义学习

【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.

顺序 选择 循环 总结

posted @ 2012-12-28 22:07  kaizenly  阅读(2064)  评论(0编辑  收藏  举报
打赏