zoukankan      html  css  js  c++  java
  • #define宏作用

    预处理器的任务
    简单来讲,预处理器的任务就是执行源代码中的预处理指令,并对源代码进行相应的处理。因此,从预处理指令的类型来讲,预处理器的任务包括如下的几个部分:
    将其他文件包含到当前文件中。
    定义宏,用来取代某些复杂文本。
    定义类似函数的宏,以更加灵活的方式控制源代码。
    实施条件编译,即有选择地编译源代码的某些部分。
     
    头文件中一般是函数、类等的声明,包含到当前文件中后,就可以在当前文件中引用头文件中的函数、类等。
     
    宏的作用
    使用预处理指令#define定义的宏主要有三个方面的作用:
    替代字面常量。
    替代运算符。
    声明某个符号已经被定义,通常用于条件编译。
     
    除了可以用宏替代字面常量,还可以用宏替代某些运算符,包括加、减、乘、除、逻辑与和逻辑非等,甚至函数和语句块的花括号。例如:
    #define ADD     +
    #define SUB     –
    #define MUL     *
    #define DIV     /
    #define AND     &&
    #define OR  ||
    #define NOT     !
    #define BEGIN {
    #define END     }
    #define OUT cout<<
    利用上述宏定义,可以编写出貌似违反C++语法、但实际上合法的源代码。例如:
    void Function()
    BEGIN
        int x = 1 ADD 2;
        int y = 3 MUL 4;
        if(NOT x OR Y)
            BEGIN
            OUT Y;
        END
    END
    说明
    除了简单地替换某些操作符,还可以定义一些类似函数的宏,即可以接受参数的宏。其定义和使用都类似于函数,但又与函数不同,详细内容请参考后面的小节。
    声明已定义符号
    利用预处理指令#define可以声明某个符号(宏名)已经定义过了,其格式如下:
    #define SOME_NAME
    如果在源代码中存在上述语句,则对预编译器来说,一个名称为SOME_NAME的宏已经被定义了,尽管没有指明要替换的文本。当然,也可以为该宏名指定要替换的文本,尽管没有必要。宏的这种特性通常应用在条件编译中。有关条件编译的内容将在后面介绍。
    预定义的宏
    在C++标准中,规定了一些预定义的宏。也就是说这些宏不需要由开发者定义,而是由预编译器提供,开发者只要使用即可。如表11-1所示是一些常用的预定义宏。
    表11-1 常用的预定义宏
    [插图]
    当心
    上述预定义宏两侧都是两道下画线,而不是一道。
    其中宏__LINE__表示该宏所在行的行号。这个行号可以用预处理指令#line进行修改。预处理指令#line的使用格式如下:
    #line新的起始行号
    如果在源代码文件中存在上述预处理指令,则该指令的下一行将以新的起始行号为编号,以后各行以此为基准进行递增。譬如#line指令定义了新的起始行号为100,则在该指令的下一行使用宏__LINE__得到的值就是100。#line指令也可以修改宏__FILE__所表示的文件名,其格式如下:
    #line新的起始行号 "新文件名"
    下例使用预定义的宏输出某些源代码的信息,程序如示例代码11.1所示。
    示例代码11.1
    #include
    #include
    using namespace std;                       // 使用名称空间std
    void fun()
    {
        cout<<"函数名:     "<<__func__<<endl;
    }
    int main(int argc, char *argv[])           // 主函数
    {
        cout<<"——输出预编译信息——"<<endl;
        cout<<"文件名:     "<<__FILE__<<endl;
        cout<<"行号:       "<<__LINE__<<endl;
        cout<<"预编译日期: "<<__DATE__<<endl;
        cout<<"预编译时间:  "<<__TIME__<<endl;
        fun();
        #line 100 "测试文件"
        cout<<"——修改行号和文件名——"<<endl;
        cout<<"文件名:     "<<__FILE__<<endl;
        cout<<"行号:       "<<__LINE__<<endl;
        system("PAUSE");                       // 暂停程序
        return EXIT_SUCCESS;
    }
    建立一个控制台工程,并将上述代码复制到源文件中,编译并运行,结果如图11-3所示。
    [插图]
    图11-3 输出预编译信息结果
    带参数的宏
    简单的宏定义,如上节例子所示,只能进行简单的文字替换,扩展能力有限。如果宏能够像函数那样带有参数,并根据参数的不同自动展开成不同的文本,则宏的扩展能力将大大提高。实际上,在C++标准中,是可以利用预处理命令#define定义带参数的宏的。
    定义带参数的宏(类似与函数格式)
    定义带参数宏的语法同定义函数类似,在紧跟宏名之后有用括号包围起来的参数列表,但没有返回值类型、参数类型等的声明。其语法如下:
    #define宏名(参数1, 参数2, , 参数n) 可替换文本
    如果可替换文本一行写不完,可以分成多行,并在每一行的结尾处加上续行符号“”(除了最后一行)。其语法如下:
    #define宏名(参数1, 参数2, , 参数n) 可替换文本行1
                                      可替换文本行2
                                     
                                      可替换文本行m
    当心
    要定义带参数的宏,则在宏名和左括号之间不能有空格(或制表符),否则就成了普通的宏定义,括号及其里面的内容也将会成为可替换文本的一部分。但是,在括号中的各参数之间可以任意添加空格。
    在可替换文本中可以引用括号中的参数,从而根据参数的不同,展开成不同的源代码文本。例如定义一个比较两数大小的宏:
    #define LESS(x, y)  x < y
    假设在程序中有如下的引用:
    bool result = LESS(3, 4);
    则经过预编译后,上述语句将展开成如下的语句:
    bool result = 3 < 4;
    在上例中,LESS是带参数宏的名称,x和y则是该宏的形式参数(类似函数的形参)。在引用LESS宏时,可以用实参(类似函数的实参)3和4分别替换形参x和y。当进行宏展开时,可替换文本中用到形参的地方也将由相应实参一一替代。
    下例定义一个宏,接受两个参数,然后比较这两个参数的大小,并输出其中的较小值,程序如示例代码11.2所示。
    示例代码11.2
    #include
    #include
    using namespace std;                    // 使用名称空间std
    // 定义宏,输出两个数中的较小值
    // 注意:以双斜杠引导的注释不能写到宏定义中,否则将成为宏的一部分
    // 但是可以加包围的注释,而且必须加在续行符之前
    #define LESS(x, y) { 
      if( x < y )
      {
        cout<<"较小值:"<<x<<endl;
      }
      else
      {
        cout<<"较小值:"<<y<<endl;
      }
    }
    int main(int argc, char *argv[])
    // 主函数
    {
      cout<<"——求较小值的宏——"<<endl;    // 输出提示信息
      LESS( 1, 2 )                           // 求1和2中的较小值,注意语句结尾没有分号
      LESS( 5, 4 )                           // 求5和4中的较小值,注意语句结尾没有分号
      cout<<endl;
      system("PAUSE");                       // 程序暂停执行
      return EXIT_SUCCESS;
    }
    建立一个控制台工程,并将上述代码复制到源文件中,编译并运行,结果如图11-4所示。
    [插图]
    图11-4 用宏求较小值并输出结果
    提示
    在上述例子中,使用了带参数的宏LESS,但是在语句的结尾处并没有分号。乍一看好像不符合C++的语法规范,但是实际上并没有错。这是因为宏是在预编译时处理的,而不是编译期。而且,宏展开后的结果符合C++语法规范,所以这些语句的结尾处没有分号并不会出错。
     
     
    特别注意:宏主要是展开,并不是那么智能,若常量等按照展开思想,如#define a(x) x+x  调用为8*a(5),本来想是8*(5+5)为80,实际是8*5+5为45
  • 相关阅读:
    广域网(ppp协议、HDLC协议)
    0120. Triangle (M)
    0589. N-ary Tree Preorder Traversal (E)
    0377. Combination Sum IV (M)
    1074. Number of Submatrices That Sum to Target (H)
    1209. Remove All Adjacent Duplicates in String II (M)
    0509. Fibonacci Number (E)
    0086. Partition List (M)
    0667. Beautiful Arrangement II (M)
    1302. Deepest Leaves Sum (M)
  • 原文地址:https://www.cnblogs.com/tangjunjun/p/11676506.html
Copyright © 2011-2022 走看看