zoukankan      html  css  js  c++  java
  • 宏定义学习

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

    顺序 选择 循环 总结

    作者:kaizen
    声明:本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此声明,且在文章明显位置给出本文链接,否则保留追究法律责任的权利。
    签名:顺序 选择 循环
  • 相关阅读:
    IsPostBack
    判断客户端.net版本
    js 汉字转换成拼音 转载
    观察者模式
    常用的js阻止冒泡的方法
    jquery中事件的绑定
    uclinux编译 skyeye运行
    dotNet学习之路 Struct与Class异同点
    dotNet学习之路 Delegate内部原理
    设计模式之旅(策略模式) 十号刚发工资的博友们,赶紧跟我一起算算你们的老板有没有给你少发工资。。。
  • 原文地址:https://www.cnblogs.com/Braveliu/p/2837954.html
Copyright © 2011-2022 走看看