zoukankan      html  css  js  c++  java
  • 14、预处理宏

    预处理宏

    预处理器(Preprocessor)定义了读取源代码、对代码预先翻译以及编写供编译器读取的新代码的过程。预处理先于编译器对源代码进行处理。

    C/C++ 语言没有内置工具在编译时间包含其他源文件、宏定义,或根据条件包含或排除一些代码行的编译时指令。预处理器提供了这些能力。虽然当前大多数编译器内部集成了预处理器,人们还是认为预处理独立于编译器的过程。预处理器读取源代码,查找预处理指令语句和宏调用,然后翻译源代码,它还去掉程序中的注释和多余的空白。

      在C++语言中预处理指令有:

     

    指令

    功能描述

    #

    空指令,没有作用

    #include

    在指令的位置包含一个源代码文件

    #define

    定义一个宏

    #undef

    取消宏定义

    #if

    如果给定条件为真,则编译代码

    #ifdef

    如果宏被定义,则编译代码

    #ifndef

    如果宏未被定义,则编译代码

    #elif

    如果前面的#if...条件不为真而当前条件为真,则编译代码

    #endif

    终止#if....#else条件块

    #error

    终止编译并显示错误信息

    #line

    修改编译器尾部用于消息报告的文件名和行号

    #pragma

    功能取决于平台

    "#"串化运算符

      宏定义内的"#"运算符把位于其后的形参所对应的实参转化为字符串。

      例子:

    #include <iostream.h>

      #define Error(n) cout << "Error " << #n

      int main(void)

    {

         Error(53);

         return 0;  

    }

     

    程序运行结果:Error 53

    http://www.cnblogs.com/mydomain/archive/2010/09/25/1834917.html

      "##"运算符

      "##"运算符把多个实参连接起来。

      #include <iostream.h>

       #deifne BookChapterVerse(b,c,v) b ## c ## v

      int main(void)

    {

         unsigned bcv=BookChapterVerse(5,12,43);

         cout << bcv;

         return 0;

    }

    #include   在指令的位置包含一个源代码文件

    头文件通常以.h结尾,其 内容可使用#include预处理器指令包含到程序中。 头文件中一般包含: 函数原型与全局变量

      形式常有下面两种

      #include <iostream>

      #include "myheader.h"

      前者<>用来引用标准库头文件,后者""常用来引用自定义的头文件

        前者<>编译器只搜索包含标准库头文件的默认目录,后者首先搜索正在编译的源文件所在的目录,找不到时再搜索包含标准库头文件的默认目录.

      如果把头文件放在其他目录下,为了查找到它,必须在双引号中指定从源文件到头文件的完整路径

      #define  定义符号、宏符号

      #define PI 3.1415925  定义符号PI3.1415925

      #define PI      取消PI的值

    或有#undef PI

        3.14159265 不是一个数值,只是一个字符串,不会进行检查

        在编译前,预处理器会遍历代码,在它认为置换有意义的地方,用字符串PI的定义值(3.14159265)来代替

       在注释或字符串中的PI不进行替换

      在C中常以#define来定义符号常量,但在C++中最好使用const 来定义常量

      #define PI 3.14159265

      const long double PI=3.14159265;

        两者比较下,前者没有类型的指定容易引起不必须的麻烦,而后者定义清楚,所以在C++中推荐使用const来定义常量

       #define的缺点:

       1)不支持类型检查

       2)不考虑作用域

       3)符号名不能限制在一个命名空间中

      用宏名中的参数带入语句中的参数

     

      #define Print(Var, digits)  count << setw(digits) << (Var) << endl

    宏后面没有;

    Print(Var)中的Print(之间不能有空格,否则(就会被解释为置换字符串的一部分调用

      Print(ival, 15);

      预处理器就会把它换成

      cout << setw(15) << (ival) << endl;

      所有的情况下都可以使用内联函数来代替宏,这样可以增强类型的检查

      template<class T>

      inline void Print (const T& var, const int& digits)

      {

          count<<setw(digits)<<var<<endl;

      }

      调用

      Print(ival, 15);

    逻辑预处理器指令#if  #else  #elif   #endif   #undef   #ifndef

     #if defined CALCAVERAGE 或 #ifdef CALCAVERAGE

       int count=sizeof(data)/sizeof(data[0]);

       for(int i=0; i<count; i++)

         average += data;

       average /= count;

      #endif

      如果已经定义符号CALCAVERAGE则把#if#endif间的语句放在要编译的源代码内

      防止重复引入某些头文件

      #ifndef COMPARE_H

      #define COMPARE_H    

    注意:这里只是定义一个没有值的符号COMPARE_H, 下面的namespace compare不是COMPARE_H的 内容,这里的定义不像是定义一个常量或宏,仅仅定义一个符号,指出此符号已定义,则就会有下面的内容

       namespace compare{

         double max(const double* data, int size);

         double min(const double* data, int size);

       }

      #endif

      比较

      #define VERSION \

       3

      因为有换行符\ 所以上句等价于 #define VERSION 3

      由此可以看出#define COMPARE_Hnamespace compare是独立没有关系的两个行。

    #line  

      使用#line可以修改__FILE__返回的字符串

      如

      #line 1000    把当前行号设置为1000

      #line 1000 "the program file"      修改__FILE__返回的字符串行号改为了1000,文件名改为了"the program file"

      #line __LINE__ "the program file"  修改__FILE__返回的字符串行号没变,文件名改为了"the program file"

    #error

      在预处理阶段,如果出现了错误,则#error指令可以生成一个诊断消息,并显示为一个编译错误,同时中止编译

      #ifndef __cplusplus

      #error "Error -  Should be C++"

      #endif

    #pragma

    专门用于实现预先定义好的选项,其结果在编译器说明文档中进行了详细的解释。编译器未识别出来的#pragma指令都会被忽略。

    assert()

    在标准库头文件<cassert>中声明

    用于在程序中 测试一个逻辑表达式,如果逻辑表达式为false, assert()会终止程序,并显示诊断消息

    用于在条件不满足就会出现重大错误,所以应确保后面的语句不应再继续执行,所以它的应用非常灵活。

    注意:assert不是错误处理 机制,逻辑表达式的结果不应产生负面效果,也不应超出程序员的控制(如找开一个文件是否成功), 程序应提供适当的代码来处理这种情况

     assert(expression);

      assert(expression) && assert(expression2);

      可以使用#define NDEBUG来关闭断言机制

    参考

    1http://www.cnblogs.com/sdywcd_coffee/archive/2010/01/06/1640653.html

  • 相关阅读:
    [翻译] GCDObjC
    [翻译] ValueTrackingSlider
    [翻译] SWTableViewCell
    使用 NSPropertyListSerialization 持久化字典与数组
    [翻译] AsyncImageView 异步下载图片
    KVC中setValuesForKeysWithDictionary:
    [翻译] Working with NSURLSession: AFNetworking 2.0
    数据库引擎
    什么是数据库引擎
    网站添加百度分享按钮代码实例
  • 原文地址:https://www.cnblogs.com/mydomain/p/1837132.html
Copyright © 2011-2022 走看看