'\" te .\" Copyright (c) 2009, 2010, Oracle and/or its affiliates.All rights reserved. .TH cpp 1 "2010 年 12 月 7 日" "SunOS 5.11" "用户命令" .SH 名称 cpp \- C 语言预处理程序 .SH 用法概要 .LP .nf \fB/usr/lib/cpp\fR [\fB-BCHMpPRT\fR] [\fB-undef\fR] [\fB-D\fR\fIname\fR] [\fB-D\fR\fIname\fR = \fIdef\fR] [\fB-I\fR\fIdirectory\fR] [\fB-U\fR\fIname\fR] [\fB-Y\fR\fIdirectory\fR] [\fIinput-file\fR [\fIoutput-file\fR]] .fi .SH 描述 .sp .LP \fBcpp\fR 是 C 语言预处理程序。\fBcpp\fR 还用作其他 Sun 编译器的第一遍操作的预处理程序。 .sp .LP 虽然 \fBcpp\fR 可以用作宏处理器,但是通常不建议这样做,因为它的输出倾向于用作编辑器的第二遍操作的输入。因此,用于 \fBcpp\fR 的首选方式是通过某个编译命令。对于通用宏处理,请参见 \fBm4\fR(1)。 .sp .LP \fBcpp\fR 可以接受两个文件名作为参数。\fI input-file\fR 和 \fIoutput-file\fR 分别是用于预处理程序的输入和输出文件。缺省情况下,它们是标准输入和标准输出。 .SH 选项 .sp .LP 支持以下选项: .sp .ne 2 .mk .na \fB\fB-B\fR\fR .ad .RS 15n .rt 支持 C++ 注释指示符 \fB/ /\fR。具有此指示符时,行上位于 \fB/ /\fR 之后的任何内容都将被视为注释。 .RE .sp .ne 2 .mk .na \fB\fB-C\fR\fR .ad .RS 15n .rt 通过预处理程序传递所有注释(位于 \fBcpp\fR 指令行上的那些注释除外)。缺省情况下,\fBcpp\fR 会剔除 C 样式的注释。 .RE .sp .ne 2 .mk .na \fB\fB-H\fR\fR .ad .RS 15n .rt 在标准错误上列显所包括文件的路径名,每行一个。 .RE .sp .ne 2 .mk .na \fB\fB-M\fR\fR .ad .RS 15n .rt 生成 makefile 依赖项的列表并将其写入到标准输出。此列表指示将基于输入文件生成的目标文件取决于输入文件以及所引用的包含文件。 .RE .sp .ne 2 .mk .na \fB\fB-p\fR\fR .ad .RS 15n .rt 仅使用前八个字符来区分预处理程序符号,并且如果在包含指令的行的末尾出现了额外的标记,则会发出警告。 .RE .sp .ne 2 .mk .na \fB\fB-P\fR\fR .ad .RS 15n .rt 对输入进行预处理,且不生成由 C 编译器的下一遍操作使用的行控制信息。 .RE .sp .ne 2 .mk .na \fB\fB-R\fR\fR .ad .RS 15n .rt 允许递归宏。 .RE .sp .ne 2 .mk .na \fB\fB-T\fR\fR .ad .RS 15n .rt 仅使用前八个字符来区分不同的预处理程序名称。包括此选项可以向后兼容始终仅使用前八个字符的系统。 .RE .sp .ne 2 .mk .na \fB\fB-undef\fR\fR .ad .RS 15n .rt 删除所有预定义的符号的初始定义。 .RE .sp .ne 2 .mk .na \fB\fB-D\fR\fIname\fR\fR .ad .RS 15n .rt 将 \fIname\fR 定义为 \fB1\fR(一)。这如同将 \fB-D\fR\fIname\fR\fB =1\fR 选项用在 \fBcpp\fR 命令行上,还等效于将 .sp .in +2 .nf \fB#define\fR \fIname\fR \fB1\fR .fi .in -2 .sp 行放在 \fBcpp\fR 正在处理的源文件中。 .RE .sp .ne 2 .mk .na \fB\fB-D\fR\fIname\fR\fB=\fR\fI def\fR\fR .ad .RS 15n .rt 定义 \fIname\fR,如同通过 \fB#define \fR 指令进行定义。这如同将 .sp .in +2 .nf \fB#define\fR \fIname\fR \fBdef\fR .fi .in -2 .sp 行放在 \fBcpp\fR 正在处理的源文件中。\fB-D\fR 选项的优先级低于 \fB-U\fR 选项。也就是说,如果在 \fB-U\fR 选项和 \fB-D\fR 选项中使用了相同的名称,则将取消定义该名称,无论这两个选项的顺序如何。 .RE .sp .ne 2 .mk .na \fB\fB-I\fR\fIdirectory\fR\fR .ad .RS 15n .rt 将 \fIdirectory\fR 插入到其名称不以 \fB /\fR 开头的 \fB#include\fR 文件的搜索路径中。\fIdirectory\fR 将被插入到 \fBinclude\fR 目录的标准列表之前。因此,将首先在具有 \fB#include\fR 行的文件的目录中搜索其名称括在双引号 (\fB"\fR) 中的 \fB#include\fR 文件,然后在由 \fB-I\fR 选项指定的目录中搜索,最后在标准列表中的目录中搜索。对于其名称括在尖括号 (\fB< >\fR) 中的 \fB#include\fR 文件,不会搜索具有 \fB#include\fR 行的文件的目录。有关此搜索顺序的确切详细信息,请参见下文中的\fB详细信息\fR。 .RE .sp .ne 2 .mk .na \fB\fB-U\fR\fIname\fR\fR .ad .RS 15n .rt 删除 \fIname\fR 的任何初始定义,其中,\fIname\fR 是由特定的预处理程序预定义的符号。下面是可能已预定义的符号的部分列表,具体取决于系统的体系结构: .sp .ne 2 .mk .na \fB操作系统:\fR .ad .RS 24n .rt \fBibm\fR、\fBgcos\fR、\fBos\fR、\fBtss\fR 和 \fBunix\fR .RE .sp .ne 2 .mk .na \fB硬件:\fR .ad .RS 24n .rt \fBinterdata\fR、\fBu3b20d\fR、\fBns32000\fR、\fBi386\fR、\fBsparc\fR 和 \fBsun\fR .RE .sp .ne 2 .mk .na \fB\fBUNIX 系统变体:\fR\fR .ad .RS 24n .rt \fBRES\fR 和 \fBRT\fR .RE .sp .ne 2 .mk .na \fB\fBlint\fR 命令:\fR .ad .RS 24n .rt \fBlint\fR .RE 针对所有 Sun 系统都定义了 \fBsun\fR、\fBsparc\fR 和 \fB unix\fR 符号。 .RE .sp .ne 2 .mk .na \fB\fB-Y\fR\fIdirectory\fR\fR .ad .RS 15n .rt 当搜索 \fB#include\fR 文件时,使用 \fIdirectory\fR 而非标准的目录列表。 .RE .SH 用法 .SS "指令" .sp .LP 所有 \fBcpp\fR 指令都以井号 (\fB#\fR) 开头,该符号是行上的第一个字符。可以在初始 \fB#\fR 之后使用空格(SPACE 或 TAB 字符)以实现合适的缩排。 .sp .ne 2 .mk .na \fB\fB#define\fR \fIname token-string\fR\fR .ad .sp .6 .RS 4n 使用 \fItoken-string\fR 替换后续的 \fIname\fR 实例。 .RE .sp .ne 2 .mk .na \fB\fB#define\fR \fIname\fR\fB (\fR\fIargument\fR [\fB,\fR \fI argument\fR] . . . \fB)\fR \fItoken-string \fR\fR .ad .sp .6 .RS 4n \fIname\fR 与 `\fB(\fR' 之间不能有空格。使用 \fItoken-string\fR 替换后续的 \fIname\fR 实例(后跟包含在括号中的参数列表),其中,\fItoken-string\fR 中的每个 \fIargument\fR 实例都将由以逗号分隔的列表中的对应标记替换。当扩展包含参数的宏时,参数将原封不动地放置到扩展的 \fItoken-string\fR 中。在整个 \fItoken-string\fR 扩展后,\fBcpp\fR 会重新开始在新创建的 \fItoken-string\fR 的开头扫描要扩展的名称。 .RE .sp .ne 2 .mk .na \fB\fB#undef\fR \fIname\fR\fR .ad .sp .6 .RS 4n 删除符号 \fIname\fR 的任何定义。在指令行上在 \fIname\fR 后不允许存在任何额外的标记。 .RE .sp .ne 2 .mk .na \fB\fB#include "\fR\fIfilename\fR\fB "\fR\fR .ad .br .na \fB\fB#include\fR \fB<\fR\fI filename\fR\fB>\fR\fR .ad .sp .6 .RS 4n 在此位置读入 \fIfilename\fR 的内容。\fBcpp\fR 在处理该数据时会将其视为当前文件的一部分。当使用了 \fB<\fR\fIfilename\fR\fB>\fR 表示法时,将仅在标准 \fBinclude\fR 目录中搜索 \fIfilename\fR。有关更多详细信息,请参见上面的 \fB-I\fR 和 \fB-Y\fR 选项。在指令行上在最后的 \fB"\fR 或 \fB>\fR 后不允许存在任何额外的标记。 .RE .sp .ne 2 .mk .na \fB\fB#line\fR \fIinteger-constant\fR\fB "\fR \fIfilename\fR\fB"\fR\fR .ad .sp .6 .RS 4n 为 C 编译器的下一遍操作生成行控制信息。\fIinteger-constant\fR 被解释为下一行的行编号,\fIfilename\fR 被解释为该行所在的文件。如果未指定 \fB"\fR\fI filename\fR\fB"\fR,则当前文件名不会改变。在指令行上在可选的 \fIfilename\fR 后不允许存在任何额外的标记。 .RE .sp .ne 2 .mk .na \fB\fB#if\fR \fIconstant-expression\fR\fR .ad .sp .6 .RS 4n 只有 \fIconstant-expression\fR 生成非零值时,后续行(直至配对的 \fB#else\fR、\fB#elif\fR 或 \fB#endif\fR 指令)才会出现在输出中。所有二元非赋值 C 运算符(包括 \fB&&\fR、\fB| |\fR 和 \fB,\fR)在 \fIconstant-expression\fR 中都是合法的。\fB?:\fR 运算符以及一元运算符 \fB-\fR、\fB!\fR 和 \fB~\fR 在 \fIconstant-expression\fR 中也是合法的。 .sp 这些运算符的优先级与针对 C 的优先级相同。此外,还可以在 \fIconstant-expression\fR 中按以下两种形式使用一元运算符 \fBdefined\fR:`\fBdefined (\fR \fIname \fR \fB)'\fR 或 `\fBdefined\fR \fI name\fR'。这允许在 \fB#if\fR 指令中实现 \fB#ifdef\fR 和 \fB #ifndef\fR 指令(在下文中描述)的效果。在 \fIconstant-expression\fR 中只应使用 \fBcpp\fR 已知的这些运算符、整数常量和名称。特别要指出的是,运算符的 \fBsize\fR\fB\fR 不可用。 .RE .sp .ne 2 .mk .na \fB\fB#ifdef\fR \fIname\fR\fR .ad .sp .6 .RS 4n 只有通过 \fB#define\fR 指令或 \fB-D\fR 选项定义了 \fIname\fR 且中间不存在 \fB#undef\fR 指令时,后续行(直至配对的 \fB#else\fR、\fB#elif\fR 或 \fB#endif\fR)才会出现在输出中。指令行上位于 \fIname\fR 之后的额外标记将被忽略且不给出提示。 .RE .sp .ne 2 .mk .na \fB\fB#ifndef\fR \fIname\fR\fR .ad .sp .6 .RS 4n 只有未定义 \fIname\fR\fI\fR 或者已通过 \fB#undef\fR 指令删除了其定义时,后续行(直至配对的 \fB#else\fR、\fB#elif\fR 或 \fB#endif\fR)才会出现在输出中。在指令行上在 \fIname\fR 后不允许存在任何额外的标记。 .RE .sp .ne 2 .mk .na \fB\fB#elif\fR \fIconstant-expression\fR\fR .ad .sp .6 .RS 4n 在 \fB#if\fR、\fB#ifdef\fR 或 \fB#ifndef\fR 指令与匹配的 \fB#else\fR 或 \fB#endif\fR 指令之间可以存在任意数目的 \fB#elif\fR 指令。只有满足以下所有条件时,位于 \fB#elif\fR 指令后的行才会出现在输出中。 .RS +4 .TP .ie t \(bu .el o 前面的 \fB#if\fR 指令中的 \fIconstant-expression\fR 的计算结果为零,前面的 \fB#ifdef\fR 中的 \fIname\fR 未定义,或者前面的 \fB#ifndef\fR 指令中的 \fIname\fR 已定义。\fI\fR .RE .RS +4 .TP .ie t \(bu .el o 中间的所有 \fB#elif\fR 指令中的 \fIconstant-expression\fR 的计算结果都为零。 .RE .RS +4 .TP .ie t \(bu .el o 当前 \fIconstant-expression\fR 的计算结果不为零。 .RE 如果 \fIconstant-expression\fR 的计算结果为非零值,则后续的 \fB#elif\fR 和 \fB#else\fR 指令(直至配对的 \fB#endif\fR)将被忽略。在 \fB#if\fR 指令中允许的任何 \fIconstant-expression\fR 在 \fB#elif\fR 指令中也受允许。 .RE .sp .ne 2 .mk .na \fB\fB#else\fR\fR .ad .sp .6 .RS 4n 这将颠倒否则会生效的条件指令的意义。如果前面的条件指示将包括这些行,则位于 \fB#else\fR 与配对的 \fB#endif\fR 之间的行将被忽略。如果前面的条件指示将忽略这些行,则在输出中将包括后续行。条件指令和对应的 \fB#else\fR 指令可以嵌套。 .RE .sp .ne 2 .mk .na \fB\fB#endif\fR\fR .ad .sp .6 .RS 4n 结束以条件指令 \fB#if\fR、\fB#ifdef\fR 或 \fB#ifndef\fR 之一开头的行区域。每个这样的指令必须有一个配对的 \fB#endif\fR。 .RE .SS "宏" .sp .LP 在 \fB#define\fR 指令主体中可以识别宏的形式参数,即使它们出现在字符常量内和用引号括起的字符串内也可识别。例如, .sp .in +2 .nf #define abc(a)|`|a| abc(xyz) .fi .in -2 .sp .sp .LP 的输出为: .sp .in +2 .nf # 1 "" |`|xyz | .fi .in -2 .sp .sp .LP 第二行是一个换行。最后的七个字符是 \fB|`|xyz| \fR(竖线、反引号、竖线、x、y、z、竖线)。在常规扫描期间,宏名称在字符常量内或用引号括起的字符串内不可识别。因此: .sp .in +2 .nf #define abc xyz printf("abc"); .fi .in -2 .sp .sp .LP 不会扩展第二行中的 \fBabc\fR,因为它在不属于 \fB#define\fR 宏定义的用引号括起的字符串内。 .sp .LP 在处理 \fB#define\fR 或 \fB#undef\fR 时不会扩展宏。因此: .sp .in +2 .nf #define abc zingo #define xyz abc #undef abc xyz .fi .in -2 .sp .sp .LP 生成 \fBabc\fR。紧跟在 \fB#ifdef\fR 或 \fB#ifndef\fR 后的标记不会扩展。 .sp .LP 在为确定另一个宏调用的实际参数而进行扫描期间,不会扩展宏。 .sp .in +2 .nf #define reverse(first,second)second first #define greeting hello reverse(greeting, #define greeting goodbye ) .fi .in -2 .sp .sp .LP 生成 .sp .in +2 .nf #define hello goodbye hello .fi .in -2 .sp .SS "输出" .sp .LP 输出包含输入文件的副本、修改内容以及如下形式的行: .sp .in +2 .nf \fB#\fR\fIlineno\fR \fB"\fR \fIfilename\fR\fB"\fR \fB"\fR\fIlevel\fR\fB"\fR .fi .in -2 .sp .sp .LP 指示以下输出行的原始源行编号和文件名,以及这是进入某个包含文件后遇到的第一个这样的行 (\fIlevel\fR=\fB1\fR)、退出某个包含文件后遇到的第一个这样的行 (\fIlevel\fR=\fB 2\fR),还是任何其他这样的行(\fIlevel\fR 为空)。 .SS "详细信息" .sp .LP 本节包含用法详细信息。 .SS "\fI目录搜索顺序\fR" .sp .LP 将按以下顺序搜索 \fB#include\fR 文件: .RS +4 .TP 1. 包含 \fB#include\fR 请求的文件的目录(也就是说,\fB#include\fR 相对于发出请求时正在扫描的文件)。 .RE .RS +4 .TP 2. 由 \fB-I\fR 选项指定的目录,按从左到右的顺序。 .RE .RS +4 .TP 3. 标准目录(\fBUNIX\fR 系统上的 \fB/usr/include\fR)。 .RE .SS "\fI特殊名称\fR" .sp .LP \fBcpp\fR 理解两个特殊名称。名称 \fB_ _LINE_ _\fR 定义为 \fBcpp\fR 已知的当前行号(一个十进制整数),\fB_ _FILE_ _\fR 定义为 \fBcpp\fR 已知的当前文件名(一个 C 字符串)。正如所定义的任何其他名称一样,它们可以用在任何位置(包括宏中)。 .SS "\fI换行符\fR" .sp .LP 换行符终止字符常量或括在引号中的字符串。可以在 \fB#define\fR 语句的主体中使用转义的换行符(即反斜杠后紧跟一个换行符)以继续在下一行上进行定义。转义的换行符不包括在宏值中。 .SS "\fI注释\fR" .sp .LP 注释将被删除(除非在命令行上使用了 \fB-C\fR 选项)。注释还将被忽略,除非注释终止了某个标记。 .SH 退出状态 .sp .LP 将返回以下退出值: .sp .ne 2 .mk .na \fB\fB0\fR\fR .ad .RS 10n .rt 成功完成。 .RE .sp .ne 2 .mk .na \fB非零\fR .ad .RS 10n .rt 出现错误。 .RE .SH 属性 .sp .LP 有关下列属性的说明,请参见 \fBattributes\fR(5): .sp .sp .TS tab() box; cw(2.75i) |cw(2.75i) lw(2.75i) |lw(2.75i) . 属性类型属性值 _ 可用性developer/build/make .TE .SH 另请参见 .sp .LP \fBm4\fR(1)、\fBattributes\fR(5) .SH 诊断 .sp .LP \fBcpp\fR 生成的错误消息是不需要加以说明的。将随诊断消息一起输出发生错误的行号和文件名。 .SH 附注 .sp .LP 当在宏的参数列表中发现了要扩展的换行符时,某些以前版本的 \fBcpp\fR 会像以前发现并扩展换行符时那样输出它们。当前版本的 \fBcpp\fR 会以 SPACE 字符替换它们。 .sp .LP 因为被包含文件的标准目录在不同的环境中可能不同,所以应当使用如下形式的 \fB#include\fR 指令: .sp .in +2 .nf \fB#include \fR .fi .in -2 .sp .LP 而不要使用带有绝对路径的指令,例如: .sp .in +2 .nf \fB#include "/usr/include/file.h"\fR .fi .in -2 .sp .LP \fBcpp\fR 会针对使用绝对路径名的情况发出警告。 .sp .LP 虽然编译器允许 8 位字符串和注释,但是其他任何位置都不允许 8 位字符串和注释。