C中的预编译宏定义45991.doc

上传人:ni****g 文档编号:543889486 上传时间:2022-12-22 格式:DOC 页数:16 大小:56.50KB
返回 下载 相关 举报
C中的预编译宏定义45991.doc_第1页
第1页 / 共16页
C中的预编译宏定义45991.doc_第2页
第2页 / 共16页
C中的预编译宏定义45991.doc_第3页
第3页 / 共16页
C中的预编译宏定义45991.doc_第4页
第4页 / 共16页
C中的预编译宏定义45991.doc_第5页
第5页 / 共16页
点击查看更多>>
资源描述

《C中的预编译宏定义45991.doc》由会员分享,可在线阅读,更多相关《C中的预编译宏定义45991.doc(16页珍藏版)》请在金锄头文库上搜索。

1、C中的预编译宏定义45991C中的预编译宏定义.txt38当乌云布满天空时,悲观的人看到的是“黑云压城城欲摧”,乐观的人看到的是“甲光向日金鳞开”。无论处在什么厄运中,只要保持乐观的心态,总能找到这样奇特的草莓。在将一个C源程序转换为可执行程序的过程中, 编译预处理是最初的步骤. 这一步骤是由预处理器(preprocessor)来完成的. 在源流程序被编译器处理之前, 预处理器首先对源程序中的宏(macro)进行处理.C初学者可能对预处理器没什么概念, 这是情有可原的: 一般的C编译器都将预处理, 汇编, 编译, 连接过程集成到一起了. 编译预处理往往在后台运行. 在有的C编译器中, 这些过程

2、统统由一个单独的程序来完成, 编译的不同阶段实现这些不同的功能. 可以指定相应的命令选项来执行这些功能. 有的C编译器使用分别的程序来完成这些步骤. 可单独调用这些程序来完成. 在gcc中, 进行编译预处理的程序被称为CPP, 它的可执行文件名为cpp.编译预处理命令的语法与C语言的语法是完全独立的. 比如: 你可以将一个宏扩展为与C语法格格不入的内容, 但该内容与后面的语句结合在一个若能生成合法的C语句, 也是可以正确编译的.(一) 预处理命令简介注意: 函数宏对参数类型是不敏感的, 你不必考虑将何种数据类型传递给宏. 那么, 如何构建对参数类型敏感的宏呢? 参考本章的第九部分, 关于#的介

3、绍. 关于定义宏的另外一些问题(1) 宏可以被多次定义, 前提是这些定义必须是相同的. 这里的相同要求先后定义中空白符出现的位置相同, 但具体的空白符类型或数量可不同, 比如原先的空格可替换为多个其他类型的空白符: 可为tab, 注释.e.g.#define NULL 0#define NULL/* null pointer */ 0上面的重定义是相同的, 但下面的重定义不同:#define fun(x) x+1#define fun(x) x + 1 或: #define fun(y) y+1如果多次定义时, 再次定义的宏内容是不同的, gcc会给出NAME redefined警告信息.应该

4、避免重新定义函数宏, 不管是在预处理命令中还是C语句中, 最好对某个对象只有单一的定义. 在gcc中, 若宏出现了重定义, gcc会给出警告.(2) 在gcc中, 可在命令行中指定对象宏的定义:e.g.$ gcc -Wall -DMAX=100 -o tmp tmp.c相当于在tmp.c中添加 #define MAX 100.那么, 如果原先tmp.c中含有MAX宏的定义, 那么再在gcc调用命令中使用-DMAX, 会出现什么情况呢?-若-DMAX=1, 则正确编译.-若-DMAX的值被指定为不为1的值, 那么gcc会给出MAX宏被重定义的警告, MAX的值仍为1.注意: 若在调用gcc的命令

5、行中不显示地给出对象宏的值, 那么gcc赋予该宏默认值(1), 如: -DVAL = -DVAL=1(3) #define所定义的宏的作用域宏在定义之后才生效, 若宏定义被#undef取消, 则#undef之后该宏无效. 并且字符串中的宏不会被识别e.g.#define ONE 1sum = ONE + TWO /* sum = 1 + TWO */#define TWO 2sum = ONE + TWO /* sum = 1 + 2 */#undef ONEsum = ONE + TWO /* sum = ONE + 2 */char c = TWO /* c = TWO, NOT 2! *

6、/(4) 宏的替换可以是递归的, 所以可以嵌套定义宏.e.g.# define ONE NUMBER_1# define NUMBER_1 1int a = ONE /* a = 1 */2, #undef#undef用来取消宏定义, 它与#define对立:#undef name如够被取消的宏实际上没有被#define所定义, 针对它的#undef并不会产生错误.当一个宏定义被取消后, 可以再度定义它.3, #if, #elif, #else, #endif#if, #elif, #else, #endif用于条件编译:#if 常量表达式1语句.#elif 常量表达式2语句.#elif 常量

7、表达式3语句.#else语句.#endif#if和#else分别相当于C语句中的if, else. 它们根据常量表达式的值来判别是否执行后面的语句. #elif相当于C中的else-if. 使用这些条件编译命令可以方便地实现对源代码内容的控制.else之后不带常量表达式, 但若包含了常量表达式, gcc只是给出警告信息.使用它们可以提升代码的可移植性-针对不同的平台使用执行不同的语句. 也经常用于大段代码注释.e.g.#if 0一大段代码;#endif常量表达式可以是包含宏, 算术运算, 逻辑运算等等的合法C常量表达式, 如果常量表达式为一个未定义的宏, 那么它的值被视为0.#if MACRO

8、_NON_DEFINED = #if 0在判断某个宏是否被定义时, 应当避免使用#if, 因为该宏的值可能就是被定义为0. 而应当使用下面介绍的#ifdef或#ifndef.注意: #if, #elif, #else之后的宏只能是对象宏. 如果name为名的宏未定义, 或者该宏是函数宏. 那么在gcc中使用-Wundef选项会显示宏未定义的警告信息.4, #ifdef, #ifndef, defined.#ifdef, #ifndef, defined用来测试某个宏是否被定义#ifdef name 或 #ifndef name它们经常用于避免头文件的重复引用:#ifndef _FILE_H_#

9、define _FILE_H_#include file.h#endifdefined(name): 若宏被定义,则返回1, 否则返回0.它与#if, #elif, #else结合使用来判断宏是否被定义, 乍一看好像它显得多余, 因为已经有了#ifdef和#ifndef. defined用于在一条判断语句中声明多个判别条件:#if defined(VAX) & defined(UNIX) & !defined(DEBUG)和#if, #elif, #else不同, #indef, #ifndef, defined测试的宏可以是对象宏, 也可以是函数宏. 在gcc中使用-Wundef选项不会显示

10、宏未定义的警告信息.5, #include , #include_next#include用于文件包含. 在#include 命令所在的行不能含有除注释和空白符之外的其他任何内容.#include headfile#include #include 预处理标记前面两种形式大家都很熟悉, #include 预处理标记中, 预处理标记会被预处理器进行替换, 替换的结果必须符合前两种形式中的某一种.实际上, 真正被添加的头文件并不一定就是#include中所指定的文件. #includeheadfile包含的头文件当然是同一个文件, 但#include 包包含的系统头文件可能是另外的文件. 但这不值

11、得被注意. 感兴趣的话可以查看宏扩展后到底引入了哪些系统头文件.关于#include headfile和#include 的区别以及如何在gcc中包含头文件的详细信息, 参考本blog的GCC笔记.相对于#include, 我们对#include_next不太熟悉. #include_next仅用于特殊的场合. 它被用于头文件中(#include既可用于头文件中, 又可用于.c文件中)来包含其他的头文件. 而且包含头文件的路径比较特殊: 从当前头文件所在目录之后的目录来搜索头文件.比如: 头文件的搜索路径一次为A,B,C,D,E. #include_next所在的当前头文件位于B目录, 那么#

12、include_next使得预处理器从C,D,E目录来搜索#include_next所指定的头文件.可参考cpp 手册进一步了解#include_next6, 预定义宏标准C中定义了一些对象宏, 这些宏的名称以_开头和结尾, 并且都是大写字符. 这些预定义宏可以被#undef, 也可以被重定义.下面列出一些标准C中常见的预定义对象宏(其中也包含gcc自己定义的一些预定义宏:_LINE_ 当前语句所在的行号, 以10进制整数标注._FILE_ 当前源文件的文件名, 以字符串常量标注._DATE_ 程序被编译的日期, 以Mmm dd yyyy格式的字符串标注._TIME_ 程序被编译的时间, 以h

13、h:mm:ss格式的字符串标注, 该时间由asctime返回._STDC_ 如果当前编译器符合ISO标准, 那么该宏的值为1_STDC_VERSION_ 如果当前编译器符合C89, 那么它被定义为199409L, 如果符合C99, 那么被定义为199901L.我用gcc, 如果不指定-std=c99, 其他情况都给出_STDC_VERSION_未定义的错误信息, 咋回事呢?_STDC_HOSTED_ 如果当前系统是本地系统(hosted), 那么它被定义为1. 本地系统表示当前系统拥有完整的标准C库.gcc定义的预定义宏:_OPTMIZE_ 如果编译过程中使用了优化, 那么该宏被定义为1._O

14、PTMIZE_SIZE_ 同上, 但仅在优化是针对代码大小而非速度时才被定义为1._VERSION_ 显示所用gcc的版本号.可参考GCC the complete reference.要想看到gcc所定义的所有预定义宏, 可以运行: $ cpp -dM /dev/null7, #line#line用来修改_LINE_和_FILE_.e.g.printf(line: %d, file: %s , _LINE_, _FILE_);#line 100 hahaprintf(line: %d, file: %s , _LINE_, _FILE_);printf(line: %d, file: %s

15、, _LINE_, _FILE_);显示:line: 34, file: 1.cline: 100, file: hahaline: 101, file: haha8, #pragma, _Pragma#pragma用编译器用来添加新的预处理功能或者显示一些编译信息. #pragma的格式是各编译器特定的, gcc的如下:#pragma GCC name token(s)#pragma之后有两个部分: GCC和特定的pragma name. 下面分别介绍gcc中常用的.(1) #pragma GCC dependencydependency测试当前文件(既该语句所在的程序代码)与指定文件(既#pragma语句最后列出的文件)的时间戳. 如果指定文件比当前文件新, 则给出警告信息.e.g.

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 生活休闲 > 社会民生

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号