预处理指令

预处理阶段,预处理器查找一行中以#号开始的预处理指令。ANSI和后来的标准都允许#号前面有空格或制表符,而且还允许在#和指令的其余部分之间有空格。

明示常量

#define 定义符号常量,还有其它用途
#undef 取消宏的定义

在#define中使用参数可以创建外形和作用与函数类似的类函数宏。带有参数的宏看上去很像函数,因为这样的宏也使用圆括号。类函数宏定义的圆括号中可以有一个或多个参数。

文件包含

#include 将被包含文件的内容输入到源文件#include指令所在的位置
包含一个大型头文件不一定显著增加程序的大小。在大部分情况下,头文件的内容是编译器生成最终代码时所需的信息,而不是添加到最终代码中的材料。

条件编译

#ifdef#else#endif指令
#ifdef 判断某个宏已经用#define定义,若已定义,则执行#else或#endif指令之前的所有指令并编译所有C代码(先出现哪个指令就执行到哪里)。如果预处理器未定义某个宏,且有#else指令,则执行#else和#endif指令之间的所有代码。
#ifdef #esle很像C的if else。两者的区别是预处理器不识别用于标记块的花括号({}),因此它使用#else和#endif来标记指令块。使用时#else不一定存在,#endif必须存在。这些指令结构可以嵌套。

#ifndef指令
#ifndef指令与#ifdef指令的用法类似,,但是它们的逻辑相反,#ifndef指令判断后面的标识符是否是未定义的。
#ifndef指令可以防止相同的宏被重复定义,例如防止多次包含一个文件。

#if#elif指令

#if很像C语言中的if,#elif很像C语言中的else-if。#if后面跟整形常量表达式,如果表达式为非零,则表达式为真。可以在指令中使用C的关系符和逻辑运算符。
可以按照if else的形式使用#elif,如:

#if SYS == 1
     #include "ibmpc.h"
#elif SYS == 2
     #include "vax.h"
#elif SYS == 3
     #include "mac.h"
#else
     #include "general.h"
#endif

较新的编译器提供另一种方法测试名称是否已定义,即用#if defined (VAX)代替#ifdef VAXdefined是一个预处理运算符,如果它的参数是用#define定义过,则返回1;否则返回。这种新方法的优点是,它可以和#elif一起使用。如:

#if defined(IBMPC)
     #include "ibmpc.h"
#elif defined(VAX)
     #include "vax.h"
#elif defined(MAC)
     #include "mac.h"
#else
     #include "general.h"
#endif

如果在VAX机上运行这几行代码,那么应该在文件前面用下面的代码定义VAX:

#define VAX

条件编译让程序移植更容易,改变文件开头部分的几个关键的定义,即可根据不同的系统设置不同的值和包含不同的文件。

预定义宏

C标准规定了一些预定义宏。

含义
__DATE__预处理的日期("Mmm dd yyyy"形式的字符串字面量,如Nov 23 2013)
__FILE__表示当前源代码文件名的字符串字面量
__LINE__表示当前源代码文件行号的整形常量
__STDC__设置为1时,表面实现遵循C标准
__STDC_HOSTED__本机环境设置为1;否则设置为0
__STDC_VERSION__支持C99标准,设置为199901L;支持C11标准,设置为201112L
__TIME__编译代码的时间,格式为"hh:mm:ss"

C99标准提供一个名为__func__的预定义标识符,它展开为一个代表函数名的字符串(该函数包含该标识符)。那么,__func__必须具有函数作用域,而从本质上看宏具有文件作用域。因此,__func__是C语言的预定义标识符,而不是预定义宏。
注意,C99新增的预定义宏和预定义标识符,不支持C99的编译器可能无法识别它们。如果使用GCC,必须设置-std=c99-std=c11

#line和#error

#line指令重置__LINE__和__FILE__宏报告的行号和文件名。

#line 1000 /* 把当前行号重置为1000 */
#line 10 "cool.c" /* 把行号重置为10,把文件名重置为cool.c */
#

#error指令让预处理器发出一条错误消息,该消息包含指令中的文本,如果可能的话,编译过程应该中断。

/* newish.c */
#if __STD_VERSION__ != 201112L
#error Not C11
#endif
gcc newish.c

输出

newish.c :2:2:error: #error Not C11

#pragma

在所有预处理指令中,#pragma指令可能是最复杂的了,它的作用是修改编译器的一些设置。它是另一种机制,用于支持因编译器而异的特性。它的语法也是因编译器而异。其一般格式为:

#pragma para

其中para为参数。
在开发过程中要用到的预编译指令#pragma要进行统一的管理和维护,要求把所有的预编译指令放到一个文档中,做成一个列表的形式,并且对每条指令进行详细的解释。不仅要说明它的使用方法、含义、作用,还要说明是在哪个函数里面用到的等等。总之,是要让别人很全面地了解你的想法,对其他使用者起到一个支持和辅助的作用。当然,如果有编译器指令的删除、修改或者添加操作,都要及时地对这个文档进行更新。而且由于#pragma是与编译器相关的,不同的编译器有不同的定义,所以,在使用过程中需要把它用函数封装起来,或者用宏定义的形式定义好,统一放到一个文件管理,而不是直接出现在函数里面。这样当编译器更改时,只需要改动一个文件或者相关函数即可。

#和##

用宏参数创建字符串:#运算符
C允许在字符串中包含宏参数。在类函数宏的替换中,#号作为一个预处理运算符,可以把记号转换为字符串。
预处理器粘合剂:##运算符
与#运算符类似,##运算符可用于类函数宏的替换部分。而且,##还可用于对象的替换部分。##运算符把两个记号组合成一个记号。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值