• c/c++中define用法详解及代码示例


    https://blog.csdn.net/u012611878/article/details/52534622

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012611878/article/details/52534622

    c++中define用法

    define在c++语言中用法比较多,这里对其进行整理。

    1.无参宏定义

    无参宏的宏名后不带参数。 
    其定义的一般形式为:

    #define  标识符  字符串
    • 1

    其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。 
    例如:

    #define MAXNUM 99999
    • 1

    这样MAXNUM就被简单的定义为99999。

    2.有参宏定义

    C++语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。 
    对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。 
    带参宏定义的一般形式为:

     #define  宏名(形参表)  字符串
    • 1

    在字符串中含有各个形参。在使用时调用带参宏调用的一般形式为:宏名(实参表); 
    例如:

    #define add(x, y) (x + y)
    int main()
    {
        cout << "1 plus 1 is " << add(1, 1.5) << ".
    ";
        //输出“1 plus 1 is 2.5.”
        system("pause");
        return(0);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这个“函数”定义了加法,但是该“函数”没有类型检查,有点类似模板,但没有模板安全,可以看做一个简单的模板。

    注意:该“函数”定义为(a + b),在这里加括号的原因是,宏定义只是在预处理阶段做了简单的替换,如果单纯的替换为a + b时,当你使用5 * add(2, 3)时,被替换为5 * 2 + 3,值为13,而非5 * (2 + 3),值为25。

    3.宏定义中的特殊操作符 
    define 中的特殊操作符有#,##和… and __VA_ARGS__ 
    (1)# 
    假如希望在字符串中包含宏参数,ANSI C允许这样作,在类函数宏的替换部分,#符号用作一个预处理运算符,它可以把语言符号转化程字符串。例如,如果x是一个宏参量,那么#x可以把参数名转化成相应的字符串。该过程称为字符串化。

    例如:

    #incldue <stdio.h>
    #define PSQR(x) printf("the square of" #x "is %d.
    ",(x)*(x))
    int main(void)
    {
        int y =4;
        PSQR(y);
        //输出:the square of y is 16.
        PSQR(2+4);
        //输出:the square of 2+4 is 36.
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    (2)##

    ##运算符可以用于类函数宏的替换部分。另外,##还可以用于类对象宏的替换部分。这个运算符把两个语言符号组合成单个语言符号。 
    例如:

    #include <stdio.h>
    #define XNAME(n) x##n
    #define PXN(n) printf("x"#n" = %d
    ",x##n)
    int main(void)
    {
        int XNAME(1)=12;//int x1=12;
        PXN(1);//printf("x1 = %d
    ", x1);
        //输出:x1=12
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (3)可变参数宏 …和__VA_ARGS__

    __VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。 
    实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点)。这样预定义宏__VA_ARGS__就可以被用在替换部分中,替换省略号所代表的字符串。

    例如:

    #define PR(...) printf(__VA_ARGS__)
    int main()
    {
        int wt=1,sp=2;
        PR("hello
    ");
        //输出:hello
        PR("weight = %d, shipping = %d",wt,sp);
        //输出:weight = 1, shipping = 2
        return 0;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    省略号只能代替最后面的宏参数。 
    #define W(x,…,y)错误! 
    但是支持#define W(x, …),此时传入的参数个数必须能够匹配。

    这里再介绍几个系统的宏:

    1) __VA_ARGS__ 是一个可变参数的宏,很少人知道这个宏,这个可变参数的宏是新的C99规范中新增的,目前似乎只有gcc支持(VC6.0的编译器不支持)。宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的”,”去掉的作用,否则会编译出错, 你可以试试。 
    2) __FILE__ 宏在预编译时会替换成当前的源文件名 
    3) __LINE__宏在预编译时会替换成当前的行号 
    4) __FUNCTION__宏在预编译时会替换成当前的函数名称

    4.宏定义中的多行定义

    非常经典。

    #define MACRO(arg1, arg2) do { /
    /* declarations */ /
    stmt1; /
    stmt2; /
    /* ... */ /
    } while(0) /* (no trailing ; ) */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    记得要在每一个换行的时候加上一个”/”

    5.宏定义中的条件编译

    在大规模的开发过程中,特别是跨平台和系统的软件里,define最重要的功能是条件编译。

    #ifdef WINDOWS
    ......
    (#else)
    ......
    #endif
    #ifdef LINUX
    ......
    (#else)
    ......
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    可以在编译的时候通过#define设置编译环境。

    6.如何取消宏

    //定义宏
    #define [MacroName] [MacroValue]
    //取消宏
    #undef [MacroName]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7.防止重复包含头文件 
    由于头文件包含可以嵌套,那么C文件就有可能包含多次同一个头文件,就可能出现重复定义的问题的。 
    通过条件编译开关来避免重复包含(重复定义) 
    例如:

    #ifndef __headerfileXXX__
    #define __headerfileXXX__
    …
    文件内容
    …
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    小结及说明

    1) 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串中可以含任何字符,可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。 
    2) 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。 
    3) 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。只要函数定义在#undefine之后,则函数无法使用#define的内容。 
    4) 宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换。 
    5) 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。 
    例如:

     #define PI 3.1415926
     #define S PI*y*y          /* PI是已定义的宏名*/
    • 1
    • 2

    6) 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。 
    7) 可用宏定义表示数据类型,使书写方便。 
    应注意用宏定义表示数据类型和用typedef定义数据说明符的区别。 
    宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。 
    请看下面的例子:

    #define PIN1 int *
    typedef (int *) PIN2;
    • 1
    • 2

    从形式上看这两者相似, 但在实际使用中却不相同。 
    下面用PIN1,PIN2说明变量时就可以看出它们的区别: 
    PIN1 a,b;在宏代换后变成: 
    int *a,b; 
    表示a是指向整型的指针变量,而b是整型变量。 
    然而: 
    PIN2 a,b; 
    表示a,b都是指向整型的指针变量。因为PIN2是一个类型说明符。由这个例子可见,宏定义虽然也可表示数据类型, 但毕竟是作字符代换。在使用时要分外小心,以避出错。 
    8) 对“输出格式”作宏定义,可以减少书写麻烦。 
    例如:

    #define P printf
    #define D "%d
    "
    #define F "%f
    "
    main(){
      int a=5, c=8, e=11;
      float b=3.8, d=9.7, f=21.08;
      P(D F,a,b);
      P(D F,c,d);
      P(D F,e,f);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    9)带参宏定义中,宏名和形参表之间不能有空格出现。 
    10)在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。 
    11)在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。

  • 相关阅读:
    git生成sshkey
    Linux中假设系统丢失了ls命令
    Linux中rpm包管理器
    Linux软件包分类
    VI编辑器
    Java多线程——多线程方法详解
    Maven 无法下载依赖包的解决方法---三步dao!!!
    7. SOFAJRaft源码分析—如何实现一个轻量级的对象池?
    动手造轮子:实现简单的 EventQueue
    java中的string对象深入了解
  • 原文地址:https://www.cnblogs.com/kelelipeng/p/10075169.html
Copyright © 2020-2023  润新知