手册页部分 1: 用户命令

退出打印视图

更新时间: 2014 年 7 月
 
 

cpp(1)

名称

cpp - C 语言预处理程序

用法概要

/usr/lib/cpp [-BCHMpPRT] [
-undef] [-Dname] [
-Dname = def] 
     [-Idirectory] [-U
name] [-Ydirectory] 
     [input-file [output-file]]

描述

cpp 是 C 语言预处理程序。cpp 还用作其他 Sun 编译器的第一遍操作的预处理程序。

虽然 cpp 可以用作宏处理器,但是通常不建议这样做,因为它的输出倾向于用作编辑器的第二遍操作的输入。因此,用于 cpp 的首选方式是通过某个编译命令。对于通用宏处理,请参见 m4(1)

cpp 可以接受两个文件名作为参数。 input-fileoutput-file 分别是用于预处理程序的输入和输出文件。缺省情况下,它们是标准输入和标准输出。

选项

支持以下选项:

–B

支持 C++ 注释指示符 / /。具有此指示符时,行上位于 / / 之后的任何内容都将被视为注释。

–C

通过预处理程序传递所有注释(位于 cpp 指令行上的那些注释除外)。缺省情况下,cpp 会剔除 C 样式的注释。

–H

在标准错误上输出所包括文件的路径名,每行一个。

–M

生成 makefile 依赖项的列表并将其写入到标准输出。此列表指示将基于输入文件生成的目标文件取决于输入文件以及所引用的包含文件。

–p

仅使用前八个字符来区分预处理程序符号,并且如果在包含指令的行的末尾出现了额外的标记,则会发出警告。

–P

对输入进行预处理,且不生成由 C 编译器的下一遍操作使用的行控制信息。

–R

允许递归宏。

–T

仅使用前八个字符来区分不同的预处理程序名称。包括此选项可以向后兼容始终仅使用前八个字符的系统。

–undef

删除所有预定义的符号的初始定义。

–Dname

name 定义为 1(一)。这如同将 –Dname =1 选项用在 cpp 命令行上,还等效于将

#define name 1

行放在 cpp 正在处理的源文件中。

–Dname= def

定义 name,如同通过 #define 指令进行定义。这如同将

#define name def

行放在 cpp 正在处理的源文件中。–D 选项的优先级低于 –U 选项。也就是说,如果在 –U 选项和 –D 选项中使用了相同的名称,则将取消定义该名称,无论这两个选项的顺序如何。

–Idirectory

directory 插入到其名称不以 / 开头的 #include 文件的搜索路径中。directory 将被插入到 include 目录的标准列表之前。因此,将首先在具有 #include 行的文件的目录中搜索其名称括在双引号 (") 中的 #include 文件,然后在由 –I 选项指定的目录中搜索,最后在标准列表中的目录中搜索。对于其名称括在尖括号 (< >) 中的 #include 文件,不会搜索具有 #include 行的文件的目录。有关此搜索顺序的确切详细信息,请参见下文中的详细信息

–Uname

删除 name 的任何初始定义,其中,name 是由特定的预处理程序预定义的符号。下面是可能已预定义的符号的部分列表,具体取决于系统的体系结构:

操作系统:

ibmgcosostssunix

硬件:

interdatau3b20dns32000i386sparcsun

UNIX 系统变体:

RESRT

lint 命令:

lint

针对所有 Sun 系统都定义了 sunsparc unix 符号。

–Ydirectory

当搜索 #include 文件时,使用 directory 而非标准的目录列表。

用法

指令

所有 cpp 指令都以井号 (#) 开头,该符号是行上的第一个字符。可以在初始 # 之后使用空格(SPACE 或 TAB 字符)以实现合适的缩排。

#define name token-string

使用 token-string 替换后续的 name 实例。

#define name (argument [, argument] . . . ) token-string

name 与 `(' 之间不能有空格。使用 token-string 替换后续的 name 实例(后跟包含在括号中的参数列表),其中,token-string 中的每个 argument 实例都将由以逗号分隔的列表中的对应标记替换。当展开包含参数的宏时,参数将原封不动地放置到展开的 token-string 中。在整个 token-string 展开后,cpp 会重新开始在新创建的 token-string 的开头扫描要展开的名称。

#undef name

删除符号 name 的任何定义。在指令行上在 name 后不允许存在任何额外的标记。

#include "filename "
#include < filename>

在此位置读入 filename 的内容。cpp 在处理该数据时会将其视为当前文件的一部分。当使用了 <filename> 表示法时,将仅在标准 include 目录中搜索 filename。有关更多详细信息,请参见上面的 –I–Y 选项。在指令行上在最后的 "> 后不允许存在任何额外的标记。

#line integer-constant " filename"

为 C 编译器的下一遍操作生成行控制信息。integer-constant 被解释为下一行的行编号,filename 被解释为该行所在的文件。如果未指定 " filename",则当前文件名不会改变。在指令行上在可选的 filename 后不允许存在任何额外的标记。

#if constant-expression

只有 constant-expression 生成非零值时,后续行(直至配对的 #else#elif#endif 指令)才会出现在输出中。所有二元非赋值 C 运算符(包括 &&| |,)在 constant-expression 中都是合法的。?: 运算符以及一元运算符 !~constant-expression 中也是合法的。

这些运算符的优先级与针对 C 的优先级相同。此外,还可以在 constant-expression 中按以下两种形式使用一元运算符 defined:`defined ( name )' 或 `defined name'。这允许在 #if 指令中实现 #ifdef #ifndef 指令(在下文中描述)的效果。在 constant-expression 中只应使用 cpp 已知的这些运算符、整数常量和名称。特别要指出的是,运算符的 size 不可用。

#ifdef name

只有通过 #define 指令或 –D 选项定义了 name 且中间不存在 #undef 指令时,后续行(直至配对的 #else#elif#endif)才会出现在输出中。指令行上位于 name 之后的额外标记将被忽略且不给出提示。

#ifndef name

只有未定义 name 或者已通过 #undef 指令删除了其定义时,后续行(直至配对的 #else#elif#endif)才会出现在输出中。在指令行上在 name 后不允许存在任何额外的标记。

#elif constant-expression

#if#ifdef#ifndef 指令与匹配的 #else#endif 指令之间可以存在任意数目的 #elif 指令。只有满足以下所有条件时,位于 #elif 指令后的行才会出现在输出中。

  • 前面的 #if 指令中的 constant-expression 的计算结果为零,前面的 #ifdef 中的 name 未定义,或者前面的 #ifndef 指令中的 name 已定义。

  • 中间的所有 #elif 指令中的 constant-expression 的计算结果都为零。

  • 当前 constant-expression 的计算结果不为零。

如果 constant-expression 的计算结果为非零值,则后续的 #elif#else 指令(直至配对的 #endif)将被忽略。在 #if 指令中允许的任何 constant-expression#elif 指令中也受允许。

#else

这将颠倒否则会生效的条件指令的意义。如果前面的条件指示将包括这些行,则位于 #else 与配对的 #endif 之间的行将被忽略。如果前面的条件指示将忽略这些行,则在输出中将包括后续行。条件指令和对应的 #else 指令可以嵌套。

#endif

结束以条件指令 #if#ifdef#ifndef 之一开头的行区域。每个这样的指令必须有一个配对的 #endif

#define 指令主体中可以识别宏的形式参数,即使它们出现在字符常量内和用引号括起的字符串内也可识别。例如,


#define abc(a)|`|a|
abc(xyz) 

的输出为:

# 1 ""
|`|xyz |

第二行是一个 NEWLINE。最后的七个字符是 |`|xyz| (竖线、反引号、竖线、x、y、z、竖线)。在常规扫描期间,宏名称在字符常量内或用引号括起的字符串内不可识别。因此:

#define abc xyz
printf("abc");

不会展开第二行中的 abc,因为它在不属于 #define 宏定义的用引号括起的字符串内。

在处理 #define#undef 时不会展开宏。因此:


#define abc zingo
#define xyz abc
#undef abc
xyz

生成 abc。紧跟在 #ifdef#ifndef 后的标记不会展开。

在为确定另一个宏调用的实际参数而进行扫描期间,不会展开宏。


#define reverse(first,second)second first
#define greeting hello
reverse(greeting,
#define greeting goodbye
)

生成

#define hello goodbye  hello

输出

输出包含输入文件的副本、修改内容以及如下形式的行:

#lineno " 
filename" "level
"

指示以下输出行的原始源行编号和文件名,以及这是进入某个包含文件后遇到的第一个这样的行 (level=1)、退出某个包含文件后遇到的第一个这样的行 (level= 2),还是任何其他这样的行(level 为空)。

详细信息

本节包含用法详细信息。

目录搜索顺序

将按以下顺序搜索 #include 文件:

  1. 包含 #include 请求的文件的目录(也就是说,#include 相对于发出请求时正在扫描的文件)。

  2. –I 选项指定的目录,按从左到右的顺序。

  3. 标准目录(UNIX 系统上的 /usr/include)。

特殊名称

cpp 理解两个特殊名称。名称 _ _LINE_ _ 定义为 cpp 已知的当前行号(一个十进制整数),_ _FILE_ _ 定义为 cpp 已知的当前文件名(一个 C 字符串)。正如所定义的任何其他名称一样,它们可以用在任何位置(包括宏中)。

Newline 字符

NEWLINE 字符终止字符常量或括在引号中的字符串。可以在 #define 语句的主体中使用转义的 NEWLINE(即反斜杠后紧跟一个 NEWLINE)以继续在下一行上进行定义。转义的 NEWLINE 不包括在宏值中。

注释

注释将被删除(除非在命令行上使用了 –C 选项)。注释还将被忽略,除非注释终止了某个标记。

退出状态

将返回以下退出值:

0

成功完成。

非零

出现错误。

属性

有关下列属性的说明,请参见 attributes(5)

属性类型
属性值
可用性
developer/build/make

另请参见

m4(1)attributes(5)

诊断

cpp 生成的错误消息是不需要加以说明的。将随诊断消息一起输出发生错误的行号和文件名。

附注

当在宏的参数列表中发现了要展开的 NEWLINE 字符时,某些以前版本的 cpp 会像以前发现并展开 NEWLINE 字符时那样输出它们。当前版本的 cpp 会以 SPACE 字符替换它们。

因为被包含文件的标准目录在不同的环境中可能不同,所以应当使用如下形式的 #include 指令:

#include <file.h>

而不要使用带有绝对路径的指令,例如:

#include "/usr/include/file.h"

cpp 会针对使用绝对路径名的情况发出警告。

虽然编译器允许 8 位字符串和注释,但是其他任何位置都不允许 8 位字符串和注释。