JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris Studio 12.2:C 用户指南
search filter icon
search icon

文档信息

前言

1.  C 编译器介绍

2.  特定于 C 编译器实现的信息

3.  并行化 C 代码

4.  lint 源代码检验器

5.  基于类型的别名分析

6.  转换为 ISO C

6.1 基本模式

6.1.1 -Xc

6.1.2 -Xa

6.1.3 -Xt

6.1.4 -Xs

6.2 旧式和新式函数的混合

6.2.1 编写新代码

6.2.2 更新现有代码

6.2.3 混合注意事项

6.3 带有可变参数的函数

6.4 提升:无符号保留与值保留

6.4.1 背景

6.4.2 编译行为

6.4.3 第一个示例:强制类型转换的使用

6.4.4 位字段

6.4.5 第二个示例:相同的结果

6.4.6 整型常量

6.4.7 第三个示例:整型常量

6.5 标记化和预处理

6.5.1 ISO C 转换阶段

6.5.2 旧 C 转换阶段

6.5.3 逻辑源代码行

6.5.4 宏替换

6.5.5 使用字符串

6.5.6 标记粘贴

6.6 constvolatile

6.6.1 类型(仅适用于 lvalue

6.6.2 派生类型中的类型限定符

6.6.3 const 意味着 readonly

6.6.4 const 用法示例

6.6.5 volatile 意味着精确语义

6.6.6 volatile 用法示例

6.7 多字节字符和宽字符

6.7.1 亚洲语言需要多字节字符

6.7.2 编码变种

6.7.3 宽字符

6.7.4 转换函数

6.7.5 C 语言特征

6.8 标准头文件和保留名称

6.8.1 标准头文件

6.8.2 保留供实现使用的名称

6.8.3 保留供扩展使用的名称

6.8.4 可安全使用的名称

6.9 国际化

6.9.1 语言环境

6.9.2 setlocale() 函数

6.9.3 更改的函数

6.9.4 新函数

6.10 表达式中的分组和求值

6.10.1 定义

6.10.2 K&R C 重新整理许可证

6.10.3 ISO C 规则

6.10.4 圆括号

6.10.5 As If 规则

6.11 不完全类型

6.11.1 类型

6.11.2 完成不完全类型

6.11.3 声明

6.11.4 表达式

6.11.5 正当理由

6.11.6 示例

6.12 兼容类型和复合类型

6.12.1 多个声明

6.12.2 分别编译兼容性

6.12.3 单编译兼容性

6.12.4 兼容指针类型

6.12.5 兼容数组类型

6.12.6 兼容函数类型

6.12.7 特殊情况

6.12.8 复合类型

7.  转换应用程序以适用于 64 位环境

8.  cscope:交互检查 C 程序

A.  按功能分组的编译器选项

B.  C 编译器选项参考

C.  实现定义的 ISO/IEC C99 行为

D.  支持的 C99 功能

E.  实现定义的 ISO/IEC C90 行为

F.  ISO C 数据表示法

G.  性能调节

H.  K&R Solaris Studio C 与 Solaris Studio ISO C 之间的差异

索引

6.5 标记化和预处理

这可能是以前的 C 版本中最少涉及的部分,涉及将每个源文件从一串字符转换为标记序列(即可进行语法分析)的操作。这些操作包括白空间(包括注释)的识别、将连续指令捆绑为标记、处理预处理指令行以及宏替换。然而,从未对其各自顺序提供保证。

6.5.1 ISO C 转换阶段

这些转换阶段的顺序由 ISO C 指定。

替换源文件中的每个三字符序列。ISO C 正好有九个为弥补不完善的字符集而单独构造的三字符序列,它们是命名 ISO 646-1983 字符集之外的字符的三字符序列:

表 6-1 三字符序列

三字符序列
转换为
??=
#
??-
~
??(
[
??)
]
??!
|
??<
{
??>
}
??/
\
??’
^

ISO C 编译器必定理解这些序列,但我们建议不要使用它们。在您使用 -xtransition 选项时,只要 ISO C 编译器在转换 (–Xt) 模式下替换三字母(甚至是在注释中),它就会向您发出警告。例如,考虑以下情形:

/* comment *??/
/* still comment? */

??/ 变为反斜杠。该字符和后面的换行符被删除。结果字符为:

/* comment */* still comment? */

第二行的第一个 / 是注释的结尾。下一个标记是 *

  1. 删除每个反斜杠/换行符对。

  2. 源文件转换为预处理标记和白空间序列。每个注释有效地替换为一个空格字符。

  3. 处理各个预处理指令并替换所有宏调用。每个 #included 源文件在其内容替换指令行之前运行较早的阶段。

  4. 解释各个换码序列(形式为字符常量和文本字符串)。

  5. 串联相邻文本字符串。

  6. 各个预处理标记转换为常规标记,编译器正确分析这些标记并生成代码。

  7. 解析所有外部对象和函数引用,形成最终程序。

6.5.2 旧 C 转换阶段

以前的 C 编译器不执行如此简单的阶段序列,也不保证何时应用这些步骤。独立预处理程序识别标记和空白的时间基本上与它替换宏和处理指令行的时间相同。然后输出由适当的编译器完全重新标记化,接着编辑器分析语言并生成代码。

由于预处理程序中标记化进程的操作时间很短,且宏替换是作为基于字符(而不是基于标记)的操作执行的,因此在预处理过程中标记和空白可能会发生很大的变化。

这两种方法存在很多差异。本节其余部分讨论代码行为如何因宏替换过程中发生的行拼接、宏替换、字符串化以及标记粘贴而更改。

6.5.3 逻辑源代码行

在 K&R C 中,仅允许将反斜杠/换行符对作为一种将指令、文本字符串或字符常量延续到下一行的方法。ISO C 扩展了该概念以便反斜杠/换行符对可以将任何内容延续到下一行。结果为逻辑源代码行。因此,依赖于反斜杠/换行符对任一侧上单独标记识别的任何代码的行为不像预期的那样。

6.5.4 宏替换

在 ISO C 之前,从未详细描述宏替换过程。这种不明确性产生很多有分歧的实现。依赖于比明显常量替换和简单类函数宏更奇特的事情的任何代码可能并不真正可移植。本手册无法指出旧 C 宏替换实现与 ISO C 版本之间的所有差异。除标记粘贴和字符串化之外的几乎所有宏替换的使用产生的标记系列均与以前完全相同。此外,ISO C 宏替换算法可以完成在旧 C 版本中无法完成的工作。例如,

#define name (*name)

使 name 的任何使用均替换为通过 name 进行的间接引用。旧 C 预处理程序会产生大量圆括号和星号,并最终产生关于宏递归的错误。

ISO C 对宏替换方法的主要更改是:要求在替换标记列表中进行替换之前针对宏参数(而不是那些本身是宏替换操作符 ### 的操作数)进行递归扩展。然而,这种更改很少在结果标记中产生实际差异。

6.5.5 使用字符串


注 - 在 ISO C 中,如果您使用 -xtransition 选项,则以下带有 ? 标记的示例将生成警告。仅在转换模式(–Xt-Xs)下,结果才与以前版本的 C 相同。


在 K&R C 中,以下代码生成文本字符串 "x y!"

#define str(a) "a!"   ?
str(x y)

因此,预处理程序在文本字符串和字符常量中查找看起来类似宏参数的字符。ISO C 认识到此功能的重要性,但不允许对部分标记的操作。在 ISO C 中,以上宏的所有调用均生成文本字符串 "a!"。为在 ISO C 中实现旧效果,我们使用 # 宏替换操作符和文本字符串串联。

#define str(a) #a "!"
str(x y)

以上代码生成两个文本字符串 "x y""!",这两个字符串串联后,会生成相同的 "x y!"

不直接替换字符常量的类似操作。此功能的主要用法与以下类似:

#define CNTL(ch) (037 & ’ch’)    ?
CNTL(L)

它生成

(037 & ’L’)

求值为 ASCII control-L 字符。我们知道的最佳解决办法是将此宏的用法更改为:

#define CNTL(ch) (037 & (ch))
CNTL(’L’)

此代码的可读性和实用性更强,因为它还可以应用于表达式。

6.5.6 标记粘贴

在 K&R C 中,将两个标记组合在一起至少有两种方法。以下代码中的两个调用均使用 x1 两个标记生成单个标识符 x1

#define self(a) a
#define glue(a,b) a/**/b ?
self(x)1
glue(x,1)

同样,ISO C 不认可这两种方法。在 ISO C 中,以上两个调用均生成两个独立标记 x1。可以通过使用 ## 宏替换操作符针对 ISO C 重新编写以上第二种方法:

#define glue(a,b) a ## b
glue(x, 1)

只有在定义了 __STDC__ 时,才应将 # 和 ## 用作宏替换操作符。由于 ## 是实际操作符,因此对于定义和调用中的空白,调用更加自由。

编译器针对未定义的 ## 运算(C 标准,第 3.4.3 节)(其中一个 ## 结果未经定义,当进行预处理时,包含多个标记而不是一个标记(C 标准,第 6.10.3.3(3) 节))发出警告诊断。未定义的 ## 运算的结果现在定义为通过预处理连接 ## 操作数所创建的字符串而生成的第一个独立标记。

没有什么直接方式可用来实现两种旧式粘贴方案中第一种方案,但是由于它在调用时引入了粘贴的任务,因此使用它的频率比使用其他形式要低。