preprocessor-宏

来源:互联网 发布:gogoing知乎 编辑:程序博客网 时间:2024/06/07 09:47

    为了让计算机能够识别并运行程序,所有的源代码必须转变为能够被计算机识别的机器码,转换的过程(以C语言为例)大致可以分为预处理-->编译-->汇编-->链接四个步骤。
    预处理指令是指程序中以#开始的语句,主要包括以下四种类型:

        (1) 宏定义指令.(#define,#undef # ##)。

        #define主要进行代码替换。#undef用于取消某个宏的定义。

       操作符#适用的格式:

       #define macro_function(x,y,z,...) #x#y#z....

    

      操作符#宏函数的参数列表替换到替换列表中。

       规则:

                1.  参数的首或尾含有一个或者多个空白字符,那么空白字符将会被删除,参数中间的大于一个连续的空白字符会保留一个空白字符。

                2. 如果参数中含有字符串文本,并且字符串中含有反斜杠\,当宏展开时,会在反斜杠'\'的前面添加一个反斜杠\。(注意转义字符)

                3. 如果参数中含有双引号'',当宏展开时,会在双引号的前面添加一个反斜杠\。(注意转义字符)

                4. 如果在替换列表中有多个##操作符或者#操作符,操作符处理的顺序不确定。

                (原文: if more than one ##operator or # operator appears in the replacement list of a macro definition, the order of evaluation of operators is not defined.)

                5. 如果宏展开的结果并不是一个有效的字符串文本,造成的结果也不确定。

              (  原文: if the result of the macro expansion is not valid character string literal, the behavior is undefined.)

      操作符##:

       规则:

           1.操作符##不能出现在替换列表中的首或者尾。

            2. 操作符##的作用是将两个token 连接成一个token,这里的token 并不一定是宏函数的参数,文本也行,例如,

             #define xy(x,y)    x##y

             连接的顺序从左到右,即是将x连接到y;x##y 和x     ##     y是等价的。原因是,##的作用是先进行分割,可以详见http://kenshinf.blog.51cto.com/1088256/252541

             3. 连接发生在宏展开之前,也就是说如果x,y 中有一个或者两个是宏,那么先将xy连接发生在其展开之前,如果连接之后还是一个有效的宏名称,那么还可以进一步展开。

             4. 如果替换列表中含有多于一个##操作符或者#操作符,操作符处理的顺序不确定。

        (2) 条件编译指令(conditional inclusions).(#ifdef,#ifndef,#if,#endif,#else 和 #elif)

        这些指令告诉预处理器在某一个条件下包含或者摒弃部分代码。

        (3)#行号控制(line control).(#line).

        为了方便编译器能够准确直观的将编译错误信息显示给用户,预处理器通常会在适当的地方插入该指令。该指令会影响__LINE__的值。
        代码片段:
/** ** This example illustrates #line directives. **/#include <stdio.h>#define LINE200 200//#line 100void func_1(){   printf("Func_1 - the current line number is %d\n",__LINE__);}//#line LINE200void func_2(){   printf("Func_2 - the current line number is %d\n",__LINE__);}int main(void){   func_1();   func_2();   while(1) {   }}

执行结果:
Func_1 - the current line number is 10
Func_2 - the current line number is 16

取消对#line的注释时,执行结果为:
Func_1 - the current line number is 102
Func_2 - the current line number is 202

        (4)错误处理指令(#error).该指令能够使得预处理器在预处理阶段产生错误消息,从而导致编译错误.该指令通常与条件编译指令一起使用,在预编译阶段进行检查。

        eg.
#define BUFFER_SIZE 255#if BUFFER_SIZE < 256#error "BUFFER_SIZE is too small."#endif


编译输出结果:
test.cpp:103:2: error: #error "BUFFER_SIZE is too small."

        (5)警告指令(#warn).与#error用法基本一致,预编译阶段产生报警。

将上述代码"#error "BUFFER_SIZE is too small""中的#error改为#warning,则编译结果为:
test.cpp:103:2: error: #warning "BUFFER_SIZE is too small."

        (6) 文件包含指令(file inclusion directives).

#include "xxxx" 表示xxx为用户自定义文件
#include <xxxx> 表示xxx为系统定义魏建.

        (7) #pargma.用于设定编译器的状态或者指示编译器完成一些特定的动作.常用语法:#pragma para.该指令较复杂,本文不对此做详细介绍.


原创粉丝点击