c语言中预处理命令都有哪些?

c语言中预处理命令都有哪些?,第1张

我们可以在C源程序中插入传给编译程序的各中指令,这些指令被称为预处理器指令,它们扩充了程序设计的环境。现把常用的预处理命令总结如下: \x0d\x0a1. 预处理程序\x0d\x0a按照ANSI标准的定义,预处理程序应该处理以下指令:\x0d\x0a#if #ifdef #ifndef #else #elif\x0d\x0a#endif\x0d\x0a#define\x0d\x0a#undef\x0d\x0a#line\x0d\x0a#error\x0d\x0a#pragma\x0d\x0a#include\x0d\x0a显然,上述所有的12个预处理指令都以符号#开始,,每条预处理指令必须独占一行。\x0d\x0a2. #define\x0d\x0a#define指令定义一个标识符和一个串(也就是字符集),在源程序中发现该标识符时,都用该串替换之。这种标识符称为宏名字,相应的替换称为宏代换。一般形式如下:\x0d\x0a#define macro-name char-sequence\x0d\x0a这种语句不用分号结尾。宏名字和串之间可以有多个空白符,但串开始后只能以新行终止。\x0d\x0a例如:我们使用LEFT代表1,用RIGHT代表0,我们使用两个#define指令:\x0d\x0a#define LEFT 1\x0d\x0a#define RIGHT 0\x0d\x0a每当在源程序中遇到LEFT或RIGHT时,编译程序都用1或0替换。\x0d\x0a定义一个宏名字之后,可以在其他宏定义中使用,例如:\x0d\x0a#define ONE 1\x0d\x0a#define TWO ONE+ONE\x0d\x0a#define THREE ONE+TWO\x0d\x0a宏代换就是用相关的串替代标识符。因此,如果希望定义一条标准错误信息时,可以如下定义:\x0d\x0a#define ERROR_MS “Standard error on input \n”\x0d\x0a如果一个串长于一行,可在行尾用反斜线”\”续行,如下:\x0d\x0a#define LONG_STRING “This is a very very long \\x0d\x0aString that is used as an example”\x0d\x0a3. #error\x0d\x0a#error指令强制编译程序停止编译,它主要用于程序调试。#error指令的一般形式是:\x0d\x0a#error error-message\x0d\x0a注意,宏串error-message不用双引号包围。遇到#error指令时,错误信息被显示,可能同时还显示编译程序作者预先定义的其他内容。\x0d\x0a4. #include\x0d\x0a程序中的#include指令要求编译程序读入另一个源文件。被读入文件的名字必须用双引号(“”)或一对尖括号()包围,例如:\x0d\x0a#include “stdio.h”\x0d\x0a#include \x0d\x0a都使C编译程序读入并编译头文件以用于I/O系统库函数。\x0d\x0a包含文件中可以包含其他#include指令,称为嵌套包含。允许的最大嵌套深度随编译器而变。\x0d\x0a文件名被双括号或尖括号包围决定了对指定文件的搜索方式。文件名被尖括号包围时,搜索按编译程序作者的定义进行,一般用于搜索某些专门放置包含文件的特殊目录。当文件名被双括号包围时,搜索按编译程序实时的规定进行,一般搜索当前目录。如未发现,再按尖括号包围时的办法重新搜索一次。\x0d\x0a通常,绝大多数程序员使用尖括号包围标准的头文件,双引号用于包围与当前程序相关的文件名。\x0d\x0a\x0d\x0a5. 条件编译指令\x0d\x0a若干编译指令允许程序员有选择的编译程序源代码的不同部分,这种过程称为条件编译。\x0d\x0a5.1#if、#else、#elif #endif\x0d\x0a条件编译指令中最常用的或许是#if,#else,#elif和#endif。这些指令允许程序员根据常数表达式的结果有条件的包围部分代码。\x0d\x0a#if的一般形式是:\x0d\x0a#if constant-expression\x0d\x0aStatement sequence\x0d\x0a#endif\x0d\x0a如#if后的常数表达式为真,则#if和#endif中间的代码被编译,否则忽略该代码段。#endif标记#if块的结束。\x0d\x0a#else指令的作用与C语言的else相似,#if指令失败时它可以作为备选指令。例如:\x0d\x0a#include \x0d\x0a#define MAX 100\x0d\x0aInt main(void)\x0d\x0a{\x0d\x0a#if MAX>99\x0d\x0aprintf(“Compiled for array greater than 99.\n”)\x0d\x0a#else\x0d\x0aprintf(“Complied for small array.\n”)\x0d\x0a#endif\x0d\x0areturn 0\x0d\x0a}\x0d\x0a注意,#else既是标记#if块的结束,也标记#else块的开始。因为每个#if只能写一个#endif匹配。\x0d\x0a#elif指令的意思是“否则,如果”,为多重编译选择建立一条if-else-if(如果-否则-如果链)。如果#if表达式为真,该代码块被编译,不测试其他#elif表达式。否则,序列中的下一块被测试,如果成功则编译之。一般形式如下:\x0d\x0a#if expression\x0d\x0aStatement sequence\x0d\x0a#elif expression1\x0d\x0aStatement sequence\x0d\x0a#elif expression2\x0d\x0aStatement sequence\x0d\x0a.\x0d\x0a.\x0d\x0a.\x0d\x0a#elif expression\x0d\x0aStatement sequence\x0d\x0a#endif\x0d\x0a5.2#ifdef和#ifndef\x0d\x0a条件编译的另一个方法是使用编译指令#ifdef和#ifndef,分别表示“如果已定义”和“如果未定义”。#ifdef的一般形式如下:\x0d\x0a#ifdef macro-name\x0d\x0aStatement sequence\x0d\x0a#endif\x0d\x0a如果macro-name原先已经被一个#define语句定义,则编译其中的代码块。\x0d\x0a#ifndef的一般形式是:\x0d\x0a#ifndef macro-name\x0d\x0aStatement sequence\x0d\x0a#endif\x0d\x0a如果macro-name当前未被#define语句定义,则编译其中的代码块。\x0d\x0a\x0d\x0a我认为,用这种,可以很方便的开启/关闭整个程序的某项特定功能。\x0d\x0a#ifdef和#ifndef都可以使用#else或#elif语句。\x0d\x0a#inlucde \x0d\x0a#define T 10\x0d\x0aInt main(void)\x0d\x0a{\x0d\x0a#ifdef t\x0d\x0aPrintf(“Hi T\n”)\x0d\x0a#else\x0d\x0aPrintf(“Hi anyone\n”)\x0d\x0a#endif\x0d\x0a#ifndef M\x0d\x0aPrintf(“M Not Defined\n”)\x0d\x0a#endif\x0d\x0aReturn 0\x0d\x0a}\x0d\x0a6. #undef\x0d\x0a#undef指令删除前面定义的宏名字。也就是说,它“不定义”宏。一般形式为:\x0d\x0a#undef macro-name\x0d\x0a7. 使用defined\x0d\x0a除#ifdef之外,还有另外一种确定是否定义宏名字的方法,即可以将#if指令与defined编译时 *** 作符一起使用。defined *** 作符的一般形式如下:\x0d\x0adefined macro-name\x0d\x0a如果macro-name是当前定义的,则表达式为真,否则为假。\x0d\x0a例如,确定宏MY是否定义,可以使用下列两种预处理命令之一:\x0d\x0a#if defined MY\x0d\x0a或\x0d\x0a#ifdef MY\x0d\x0a也可以在defined之前加上感叹号”!”来反转相应的条件。例如,只有在DEBUG未定义的情况下才编译。\x0d\x0a#if !defined DEBUG\x0d\x0aPrintf(“Final Version!\n”)\x0d\x0a#endif\x0d\x0a使用defined的一个原因是,它允许由#elif语句确定的宏名字存在。\x0d\x0a8. #line\x0d\x0a#line指令改变__LINE__和__FILE__的内容。__LINE__和__FILE__都是编译程序中预定义的标识符。标识符__LINE__的内容是当前被编译代码行的行号,__FILE__的内容是当前被编译源文件的文件名。#line的一般形式是:\x0d\x0a#line number “filename”\x0d\x0a其中,number是正整数并变成__LINE__的新值;可选的“filename”是合法文件标识符并变成__FILE__的新值。#line主要用于调试和特殊应用。\x0d\x0a\x0d\x0a9. #pragma\x0d\x0a#pragma是编译程序实现时定义的指令,它允许由此向编译程序传入各种指令。例如,一个编译程序可能具有支持跟踪程序执行的选项,此时可以用#pragma语句选择该功能。编译程序忽略其不支持的#pragma选项。#pragma提高C源程序对编译程序的可移植性。\x0d\x0a10. 预处理 *** 作符#和##\x0d\x0a有两个预处理 *** 作符:#和##,它们可以在#define中使用。\x0d\x0a *** 作符#通常称为字符串化的 *** 作符,它把其后的串变成用双引号包围的串。例如:\x0d\x0a#include \x0d\x0a#define mkstr(s) #s\x0d\x0aint main(void)\x0d\x0a{\x0d\x0aPrintf(mkstr(I like C))\x0d\x0aReturn 0\x0d\x0a}\x0d\x0a预处理程序把以下的语句:\x0d\x0aPrintf(mkstr(I like C))\x0d\x0a变成\x0d\x0aPrintf(“I like C”)\x0d\x0a *** 作符##把两个标记拼在一起,形成一个新标记。例如:\x0d\x0a#include \x0d\x0a#define concat(a,a) a##b\x0d\x0aint main(void)\x0d\x0a{\x0d\x0aInt xy = 10\x0d\x0aPrintf(“%d”,concat(x,y))\x0d\x0aReturn 0\x0d\x0a}\x0d\x0a预处理程序把以下语句:\x0d\x0aPrintf(“%d”,concat(x,y))\x0d\x0a变成\x0d\x0aPrintf(“%d”,xy)\x0d\x0a *** 作符#和##主要作用是允许预处理程序对付某些特殊情况,多数程序中并不需要。\x0d\x0a11. 预定义宏\x0d\x0aC规范了5个固有的预定义宏,它们是:\x0d\x0a__LINE__\x0d\x0a__FILE__\x0d\x0a__DATE__\x0d\x0a__TIME__\x0d\x0a__STDC__\x0d\x0a__LINE__和__FILE__包含正在编译的程序的行号和文件名。\x0d\x0a__DATE__和内容形如month/day/year(月/日/年)的串,代表源文件翻译成目标码的日期。\x0d\x0a__TIME__中的串代表源代码编译成目标码的时间,形如hour:minute:second(时:分:秒)\x0d\x0a如果__STDC__的内容是十进制常数1,则表示编译程序的实现符合标准C。

编译,编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照 *** 作系统对可执行文件格式的要求链接生成可执行程序。

如果用一张图来表示:

读取c源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理

[析] 伪指令主要包括以下四个方面

(1)宏定义指令,如#define Name TokenString,#undef等。对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的'出现不再被替换。

(2)条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif,等等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉

(3)头文件包含指令,如#include "FileName"或者#include 等。在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。

包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在/usr/include目录下。在程序中#include它们要使用尖括号(<>)。另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。

(4)特殊符号,预编译程序可以识别一些特殊的符号。例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。

注意:

预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。

所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。预处理是C语言的一个重要功能, 它由预处理程序负责完成。当对一个源文件进行编译时, 系统把自动引用预处理程序对源程序中的预处理部分作处理, 处理完毕自动进入对源程序的编译。

C语言提供了多种预处理功能,如宏定义、文件包含、 条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、 移植和调试,也有利于模块化程序设计。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7738248.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-09
下一篇 2023-04-09

发表评论

登录后才能评论

评论列表(0条)

保存