29.11.2014 Views

MISRA-C-:2004 - 错误提示:发生了异常

MISRA-C-:2004 - 错误提示:发生了异常

MISRA-C-:2004 - 错误提示:发生了异常

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>MISRA</strong><br />

The Motor Industry Software Reliability Association<br />

<strong>MISRA</strong>-C-:<strong>2004</strong><br />

Guidelines<br />

for the use<br />

of the<br />

C language<br />

in critical systems<br />

中 文 版


1 背 景 —— C 的 使 用 和 问 题 ........................................................................................ 3<br />

1.1 汽 车 工 业 中 C 的 使 用 .......................................................................................................... 3<br />

1.2 语 言 的 不 安 全 性 和 C 语 言 .................................................................................................. 3<br />

1.3 安 全 相 关 系 统 中 C 的 使 用 .................................................................................................. 4<br />

1.4 标 准 化 .................................................................................................................................. 5<br />

2 <strong>MISRA</strong>-C: 视 野 .......................................................................................................... 6<br />

2.1 <strong>MISRA</strong>-C 的 发 布 说 明 ........................................................................................................ 6<br />

2.2 <strong>MISRA</strong>-C 的 目 标 ................................................................................................................ 6<br />

3 <strong>MISRA</strong>-C: 范 围 .......................................................................................................... 7<br />

3.1 基 本 的 语 言 问 题 .................................................................................................................. 7<br />

3.2 未 指 出 的 问 题 ...................................................................................................................... 7<br />

3.3 可 应 用 性 .............................................................................................................................. 7<br />

3.4 预 备 知 识 .............................................................................................................................. 7<br />

3.5 C++ 问 题 ............................................................................................................................... 7<br />

3.6 自 动 产 生 代 码 的 问 题 .......................................................................................................... 8<br />

4 使 用 <strong>MISRA</strong>-C............................................................................................................. 9<br />

4.1 软 件 工 程 环 境 ...................................................................................................................... 9<br />

4.2 编 程 语 言 和 编 码 环 境 .......................................................................................................... 9<br />

4.3 采 用 子 集 (subset).......................................................................................................... 11<br />

4.4 符 合 性 声 明 (Claiming compliance) ............................................................................ 13<br />

4.5 持 续 改 进 ............................................................................................................................ 13<br />

5 规 则 简 介 ..................................................................................................................... 14<br />

5.1 规 则 分 类 ............................................................................................................................ 14<br />

5.2 规 则 的 组 织 ........................................................................................................................ 14<br />

5.3 规 则 的 冗 余 ........................................................................................................................ 14<br />

5.4 规 则 的 形 式 ........................................................................................................................ 14<br />

5.5 理 解 原 始 参 考 .................................................................................................................... 15<br />

5.6 规 则 的 范 围 ........................................................................................................................ 17<br />

6 规 则 ............................................................................................................................. 18<br />

6.1 环 境 .................................................................................................................................... 18<br />

6.2 语 言 扩 展 ............................................................................................................................ 19<br />

6.3 文 档 .................................................................................................................................... 19<br />

6.4 字 符 集 ................................................................................................................................21<br />

6.5 标 识 符 ................................................................................................................................21<br />

1


6.6 类 型 .................................................................................................................................... 23<br />

6.7 常 量 .................................................................................................................................... 24<br />

6.8 声 明 与 定 义 ........................................................................................................................ 25<br />

6.9 初 始 化 ................................................................................................................................27<br />

6.10 数 值 类 型 转 换 ................................................................................................................ 27<br />

6.11 指 针 类 型 转 换 .................................................................................................................... 36<br />

6.12 表 达 式 ............................................................................................................................ 37<br />

6.13 控 制 语 句 表 达 式 ............................................................................................................ 43<br />

6.14 控 制 流 ............................................................................................................................ 45<br />

6.15 switch 语 句 ......................................................................................................................... 48<br />

6.16 函 数 ................................................................................................................................50<br />

6.17 指 针 和 数 组 .................................................................................................................... 51<br />

6.18 结 构 与 联 合 .................................................................................................................... 54<br />

6.19 预 处 理 指 令 .................................................................................................................... 57<br />

6.20 标 准 库 ............................................................................................................................ 62<br />

6.21 运 行 时 错 误 .................................................................................................................... 64<br />

7 References................................................................................................................... 66<br />

Appendix A: Summary of rules....................................................................................... 68<br />

Appendix B:<strong>MISRA</strong>-C :1998 到 <strong>MISRA</strong>-C :<strong>2004</strong> 规 则 映 射 .............. 74<br />

Appendix C:<strong>MISRA</strong>-C:1998 – 已 废 除 的 规 则 .............................................................. 81<br />

Appendix D:ISO 标 准 交 互 参 考 .................................................................................... 82<br />

Appendix E : 术 语 表 ....................................................................................................... 85<br />

2


1 背 景 —— C 的 使 用 和 问 题<br />

1.1 汽 车 工 业 中 C 的 使 用<br />

<strong>MISRA</strong>-C:1998 [1] 发 布 于 1998 年 。 本 文 档 是 它 的 修 订 版 本 , 用 来 解 决 与 第 一 版 本 有 关 系<br />

的 问 题 。<br />

在 汽 车 工 业 领 域 的 实 时 嵌 入 式 应 用 中 ,C 编 程 语 言 的 使 用 越 来 越 体 现 出 广 泛 性 和 重 要 性 。<br />

这 在 相 当 程 度 上 取 决 于 该 语 言 固 有 的 灵 活 性 、 可 支 持 的 范 围 及 其 潜 在 的 访 问 广 泛 硬 件 环 境 的<br />

可 移 植 性 。 详 细 的 理 由 包 括 :<br />

• 对 于 许 多 使 用 中 的 微 处 理 器 来 说 , 如 果 存 在 其 他 除 了 汇 编 语 言 之 外 的 可 用 语 言 , 通<br />

常 就 是 C。 在 许 多 情 况 下 , 其 他 语 言 根 本 就 不 可 用 于 硬 件 。<br />

• C 对 高 速 、 底 层 、 输 入 / 输 出 操 作 等 提 供 了 很 好 的 支 持 , 而 这 些 特 性 是 许 多 汽 车 嵌 入<br />

式 系 统 的 基 本 特 性 。<br />

• 由 于 应 用 的 逐 步 增 长 的 复 杂 性 , 高 级 语 言 的 使 用 较 汇 编 语 言 更 为 适 合 。<br />

• 相 对 于 其 他 一 些 高 级 语 言 ,C 能 够 产 生 较 小 的 和 较 少 RAM 密 集 性 (RAM-intensive)<br />

的 代 码 。<br />

• 增 长 的 可 移 植 性 需 求 。 市 场 竞 争 要 求 在 工 程 项 目 生 命 周 期 的 任 何 阶 段 , 软 件 可 以 通<br />

过 移 植 到 新 的 和 / 或 低 成 本 的 处 理 器 , 目 的 是 为 了 降 低 硬 件 成 本 。<br />

• 增 长 的 自 动 产 生 C 代 码 的 使 用 要 求 。C 代 码 需 要 从 模 型 包 中 自 动 产 生 。<br />

• 增 长 的 对 开 放 系 统 和 主 机 环 境 (hosted enviroments) 的 兴 趣 。<br />

1.2 语 言 的 不 安 全 性 和 C 语 言<br />

没 有 哪 种 编 程 语 言 能 够 保 证 最 终 的 可 执 行 代 码 会 准 确 地 按 照 程 序 员 预 想 的 那 样 执 行 。 任<br />

何 语 言 都 会 产 生 大 量 的 问 题 , 下 面 为 其 做 了 广 泛 的 分 类 , 并 描 述 了 C 语 言 不 安 全 性 的 例 子 。<br />

1.2.1 程 序 员 产 生 错 误<br />

程 序 员 产 生 的 错 误 , 简 单 的 可 以 是 变 量 名 字 的 书 写 错 误 , 或 者 更 为 复 杂 的 错 误 , 如 对 算<br />

法 的 误 解 。 编 程 语 言 可 以 承 受 这 样 的 错 误 。 首 先 , 语 言 的 风 格 和 表 达 能 帮 助 或 提 示 程 序 员 清<br />

晰 考 虑 其 算 法 。 其 次 , 对 于 书 写 错 误 , 语 言 可 以 使 从 一 个 有 效 结 构 向 另 一 个 有 效 ( 不 是 预 想<br />

的 ) 结 构 的 转 换 变 得 轻 松 或 困 难 。 第 三 , 当 错 误 发 生 时 , 语 言 可 以 检 测 到 也 可 能 检 测 不 到 。<br />

首 先 , 关 于 语 言 的 风 格 和 表 达 , 使 用 C 可 以 编 写 出 良 好 布 局 的 、 结 构 化 的 和 表 达 性 强 的<br />

代 码 。 还 可 以 使 用 它 编 写 出 不 正 当 的 和 特 别 难 以 理 解 的 代 码 。 很 明 显 , 后 者 对 于 安 全 相 关 的<br />

系 统 是 不 可 接 受 的 。<br />

其 次 ,C 的 语 法 特 性 足 以 使 得 书 写 错 误 也 能 产 生 完 全 有 效 的 代 码 。 例 如 , 在 “==”( 逻<br />

辑 比 较 ) 的 地 方 写 成 “=”( 赋 值 ) 是 很 常 见 的 , 而 且 最 终 结 果 也 几 乎 总 是 有 效 的 ( 但 它 是 错<br />

误 的 ); 而 if 语 句 的 结 尾 出 现 的 多 余 分 号 能 完 全 改 变 代 码 逻 辑 。<br />

第 三 ,C 的 基 本 观 点 是 假 设 程 序 员 知 道 他 们 在 做 什 么 , 这 意 味 着 错 误 即 使 出 现 也 不 会 被 语<br />

言 注 意 到 而 通 过 。 在 这 方 面 C 体 现 出 的 软 弱 性 正 在 于 它 的 “ 书 写 检 查 ”(type checking)。 举 例<br />

来 说 ,C 不 会 拒 绝 程 序 员 在 使 用 整 数 代 表 true/false 值 时 却 在 该 整 数 中 存 储 了 浮 点 值 。 大 多 数<br />

这 样 的 失 配 可 以 简 单 地 通 过 强 制 使 其 合 适 。 如 果 C 的 表 现 不 得 其 所 (a square peg and a round),<br />

3


它 不 会 挑 剔 而 会 适 合 它 们 !<br />

1.2.2 程 序 员 不 了 解 语 言<br />

程 序 员 可 能 会 误 解 语 言 构 造 的 作 用 。 对 这 样 的 误 解 , 一 些 语 言 是 更 为 开 放 的 。<br />

C 语 言 中 有 相 当 多 的 地 方 能 使 程 序 员 轻 易 产 生 误 解 。 例 如 运 算 符 优 先 级 的 规 则 。 这 些 规 则<br />

是 良 好 定 义 的 , 但 也 非 常 复 杂 , 也 很 容 易 对 某 特 定 表 达 式 中 运 算 符 的 优 先 级 做 出 错 误 的 假 设 。<br />

1.2.3 编 译 器 的 行 为 同 程 序 员 预 期 的 不 同<br />

如 果 语 言 具 有 未 经 完 善 定 义 的 特 性 , 或 者 模 糊 特 性 , 那 么 在 程 序 员 认 为 某 个 构 造 应 该 如<br />

此 时 , 编 译 器 的 解 释 却 是 完 全 不 同 的 。<br />

C 语 言 中 许 多 地 方 是 未 经 完 善 定 义 的 , 因 此 其 行 为 可 能 会 随 着 编 译 器 的 改 变 而 改 变 。 某 些<br />

情 况 下 , 其 行 为 甚 至 在 同 一 个 编 译 器 内 也 会 根 据 上 下 文 而 发 生 变 化 。Annex G 中 所 有 的 C 标<br />

准 列 出 了 201 个 这 种 问 题 。 这 可 以 提 出 相 当 多 的 问 题 , 特 别 是 在 面 临 编 译 器 间 的 移 植 性 时 。<br />

然 而 ,C 标 准 [2] 列 出 了 这 些 问 题 , 所 以 它 们 能 为 我 们 所 知 。<br />

1.2.4 编 译 器 包 含 错 误<br />

语 言 的 编 译 器 ( 及 其 链 接 器 等 ) 本 身 就 是 软 件 工 具 。 编 译 器 可 能 不 会 始 终 正 确 地 编 译 代<br />

码 。 例 如 , 在 特 定 环 境 下 它 们 可 能 同 语 言 标 准 相 违 背 , 或 者 其 本 身 可 能 就 包 含 “bug”。<br />

因 为 C 语 言 中 存 在 许 多 难 以 理 解 的 地 方 , 编 译 器 的 编 写 者 很 容 易 错 误 地 解 释 和 实 现 标 准 。<br />

语 言 的 某 些 地 方 比 其 他 的 更 容 易 这 样 。 而 且 编 译 器 的 编 写 者 有 时 会 有 意 改 变 标 准 。<br />

1.2.5 运 行 时 错 误<br />

有 些 不 同 的 语 言 问 题 产 生 自 正 确 编 译 的 代 码 , 但 某 些 特 殊 数 据 会 在 代 码 运 行 时 产 生 错 误 。<br />

语 言 能 够 对 可 执 行 代 码 内 部 做 运 行 时 的 检 查 以 检 测 这 样 的 错 误 并 执 行 适 当 的 动 作 。<br />

通 常 ,C 的 运 行 时 检 查 能 力 比 较 弱 。 这 也 是 C 代 码 短 小 有 效 的 原 因 之 一 , 但 是 在 运 行 中<br />

检 查 错 误 就 要 花 费 一 定 的 代 价 。C 编 译 器 通 常 不 为 某 些 常 见 问 题 提 供 运 行 时 检 查 , 诸 如 数 学 异<br />

常 ( 如 零 除 )、 溢 出 、 指 针 地 址 的 有 效 性 , 或 数 组 越 界 错 误 。<br />

1.3 安 全 相 关 系 统 中 C 的 使 用<br />

从 1.2 节 可 以 清 楚 地 知 道 , 在 安 全 相 关 系 统 中 使 用 C 语 言 需 要 相 当 小 心 。 针 对 上 面 提 及 的<br />

问 题 种 类 , 已 经 为 安 全 相 关 系 统 中 C 的 使 用 提 出 了 许 多 需 要 关 注 的 事 情 。 显 然 地 , 不 能 为 安<br />

全 相 关 系 统 使 用 所 有 的 C 语 言 特 性 。<br />

然 而 , 做 为 语 言 来 说 ,C 是 非 常 成 熟 的 , 在 实 践 中 也 是 经 过 了 良 好 分 析 和 使 用 的 。 所 以 它<br />

的 不 足 也 是 众 所 周 知 和 可 以 理 解 的 。 同 时 可 获 得 大 量 的 商 业 工 具 支 持 , 这 些 工 具 用 来 静 态 检<br />

查 C 源 代 码 和 提 醒 程 序 员 语 言 问 题 的 存 在 。<br />

如 果 为 了 实 践 的 原 因 有 必 要 在 安 全 相 关 系 统 中 使 用 C 语 言 , 那 么 必 须 对 语 言 的 使 用 加 以<br />

限 制 , 避 免 那 些 确 实 可 以 产 生 问 题 的 地 方 , 直 到 它 是 可 以 应 用 的 。 本 文 档 为 人 们 提 供 了 这 样<br />

的 限 制 集 合 ( 通 常 称 为 “ 语 言 子 集 ”(language subset))。<br />

Hatton [3] 认 为 , 倘 若 强 加 了 “…… 严 格 和 自 动 的 强 制 性 约 束 ……”, 那 么 C 能 够 写 出 “……<br />

至 少 同 其 他 通 用 语 言 一 样 的 具 有 高 质 量 和 一 致 性 的 软 件 ”。<br />

注 意 , 相 对 于 C 语 言 , 汇 编 语 言 不 再 适 合 于 安 全 相 关 系 统 , 在 某 些 方 面 还 会 更 坏 。 通 常<br />

不 建 议 在 安 全 相 关 系 统 中 使 用 汇 编 语 言 , 即 使 使 用 也 要 加 以 非 常 严 格 的 约 束 。<br />

4


1.4 标 准 化<br />

本 文 档 使 用 的 标 准 是 由 ISO 9899:1990 [2] 定 义 的 C 编 程 语 言 , 它 是 由 ISO/IEC<br />

9899/COR1:1995 [4]、ISO/IEC 9899/AMD1:1995 [5] 和 ISO/IEC 9899/COR2:1996 [6] 修 订 的 。 为<br />

了 简 便 , 本 文 档 中 统 称 为 “C90”。 基 本 的 1990 年 文 档 [7] 是 ANSI X3.159-1989 [2] 的 ISO 版 本 。<br />

在 内 容 上 ,ISO/IEC 标 准 同 ANSI 标 准 是 一 致 的 。 然 而 要 说 明 的 是 , 两 个 标 准 中 章 节 的 编 号 是<br />

不 同 的 , 本 文 档 的 章 节 编 号 随 同 ISO 标 准 。<br />

还 要 说 明 的 是 ,ANSI 标 准 [7] 包 含 了 一 个 有 用 的 附 录 , 其 中 在 某 些 由 标 准 委 员 会 制 定 的 决<br />

策 后 给 出 了 相 关 的 说 明 解 释 。ISO 版 本 中 没 有 这 样 的 附 录 。<br />

工 作 小 组 已 经 开 始 考 虑 ISO/IEC 9899:1999[8]( 称 为 “C99”)。 在 本 文 档 的 发 布 日 期 (<strong>2004</strong><br />

年 10 月 ), 还 没 出 现 嵌 入 了 C99 的 商 业 编 译 器 。<br />

5


2 <strong>MISRA</strong>-C: 视 野<br />

2.1 <strong>MISRA</strong>-C 的 发 布 说 明<br />

<strong>MISRA</strong> 协 会 在 1994 年 发 布 了 它 的 “Development Guidelines for Vehicle Based Software”[9],<br />

描 述 了 软 件 开 发 过 程 中 所 有 应 该 使 用 的 方 法 集 。 特 别 地 , 在 使 用 中 因 为 考 虑 安 全 集 成 度 而 做<br />

出 的 语 言 、 编 译 器 和 语 言 特 性 的 选 择 , 成 为 首 要 考 虑 的 事 情 。<strong>MISRA</strong> 指 南 [9] 中 的 节 3.2.4.3(b)<br />

和 表 3 描 述 了 这 些 。 推 荐 的 方 法 之 一 是 使 用 已 经 应 用 于 航 空 、 能 源 和 国 防 工 业 中 的 标 准 化 的<br />

语 言 子 集 。 本 文 档 定 义 了 这 样 一 个 合 适 的 C 语 言 子 集 。<br />

2.2 <strong>MISRA</strong>-C 的 目 标<br />

在 发 布 这 个 关 于 C 编 程 语 言 使 用 的 文 档 时 ,<strong>MISRA</strong> 协 会 并 没 想 促 进 C 在 汽 车 工 业 中 的 应<br />

用 , 而 是 因 为 认 识 到 了 C 的 广 泛 应 用 。 本 文 档 的 目 标 是 为 了 促 进 该 语 言 的 最 为 安 全 的 使 用 。<br />

<strong>MISRA</strong> 协 会 希 望 本 文 档 能 获 得 工 业 上 的 接 受 , 以 及 对 更 安 全 子 集 的 采 用 能 够 成 为 汽 车 制<br />

造 业 和 许 多 零 部 件 供 应 商 的 最 佳 实 践 。 它 也 应 该 为 通 用 C 和 该 特 殊 子 集 的 使 用 增 加 培 训 和 增<br />

强 使 用 能 力 , 无 论 是 在 个 人 层 次 还 是 公 司 范 围 。<br />

大 部 分 重 点 放 在 了 静 态 检 查 工 具 上 以 强 制 对 子 集 的 适 应 , 同 时 希 望 这 也 会 成 为 汽 车 嵌 入<br />

式 系 统 开 发 者 的 普 遍 实 践 。<br />

尽 管 许 多 学 术 著 作 对 语 言 及 其 正 反 两 面 做 了 大 量 的 描 述 , 但 这 方 面 信 息 在 汽 车 开 发 中 还<br />

不 是 广 为 人 知 。 本 文 档 的 另 外 一 个 目 标 就 是 使 汽 车 工 业 中 的 工 程 师 和 经 理 们 越 来 越 多 地 关 心<br />

语 言 的 选 用 问 题 。<br />

可 以 帮 助 进 行 软 件 开 发 的 工 具 , 尤 其 是 支 持 C 语 言 使 用 的 工 具 对 我 们 来 说 是 个 好 处 。 然<br />

而 , 对 设 计 与 实 现 的 鲁 棒 性 的 关 注 是 始 终 存 在 的 , 特 别 是 对 安 全 相 关 软 件 的 开 发 。 人 们 希 望<br />

汽 车 工 业 中 正 在 使 用 的 实 现 软 件 最 佳 实 践 ( 通 过 <strong>MISRA</strong> 指 南 [9] 和 本 文 档 ) 的 方 法 能 鼓 励<br />

COTS 工 具 的 供 应 商 使 用 它 以 保 证 其 产 品 适 合 于 汽 车 工 业 应 用 。<br />

6


3 <strong>MISRA</strong>-C: 范 围<br />

3.1 基 本 的 语 言 问 题<br />

<strong>MISRA</strong> 指 南 [9]( 表 3) 要 求 使 用 “ 标 准 化 结 构 化 语 言 的 受 限 子 集 ”。 对 C 来 说 , 这 意 味<br />

着 只 能 使 用 在 ISO 标 准 中 定 义 的 语 言 , 因 此 排 除 了 以 下 方 面 的 使 用 :<br />

• K&R C( 由 Kernighan 和 Ritchie 编 写 的 “The C Programming language” 的 第 一 版 )<br />

• C++<br />

• C 的 私 有 扩 展<br />

3.2 未 指 出 的 问 题<br />

风 格 和 代 码 度 量 问 题 在 一 定 程 度 上 是 很 个 人 化 的 。 对 任 何 一 群 人 来 说 都 很 难 赞 成 什 么 是<br />

适 当 的 , 而 要 <strong>MISRA</strong> 给 出 确 定 性 的 建 议 也 是 不 合 适 的 。 重 要 的 不 是 使 用 者 采 取 了 哪 种 确 切 的<br />

风 格 或 者 特 定 的 度 量 , 而 是 使 用 者 要 定 义 风 格 指 南 和 合 适 的 度 量 与 限 制 ( 见 节 4.2.2 和 4.2.4)。<br />

<strong>MISRA</strong> 协 会 的 角 色 不 是 建 议 特 定 的 供 应 商 或 工 具 强 制 执 行 所 采 取 的 约 束 。 使 用 本 文 档 的<br />

用 户 在 选 择 工 具 上 是 自 由 的 , 鼓 励 供 应 商 提 供 遵 循 规 则 的 工 具 。 本 文 档 用 户 的 负 担 是 要 声 明<br />

其 工 具 充 分 地 遵 循 了 规 则 。<br />

3.3 可 应 用 性<br />

本 文 档 被 设 计 为 应 用 在 汽 车 嵌 入 式 系 统 的 产 品 代 码 上 。<br />

根 据 ISO 9899[2]( 节 5.1.2) 中 定 义 的 执 行 环 境 , 本 文 档 的 目 标 定 在 “ 自 立 (free-standing)<br />

的 环 境 ”, 尽 管 它 也 描 述 了 库 的 问 题 , 因 为 嵌 入 式 编 译 器 中 经 常 也 会 用 到 一 些 标 准 库 。<br />

如 果 合 适 , 本 文 档 的 大 部 分 要 求 也 可 以 应 用 在 其 他 嵌 入 式 领 域 。 对 主 机 系 统 (hosted<br />

system) 的 应 用 , 本 文 档 的 要 求 不 是 必 需 的 。<br />

在 进 行 编 译 器 和 静 态 工 具 的 比 较 检 测 (benchmark) 时 也 不 需 完 全 应 用 本 文 档 规 则 , 有 时<br />

在 比 较 工 具 时 有 必 要 打 破 这 些 规 则 , 以 测 量 工 具 的 响 应 。<br />

3.4 预 备 知 识<br />

本 文 档 不 是 要 做 为 所 涉 主 题 的 介 绍 和 培 训 。 而 是 认 为 读 者 熟 悉 ISO C 编 程 语 言 标 准 和 相<br />

关 工 具 , 并 读 过 了 主 要 的 引 用 文 档 。 同 样 假 设 读 者 已 经 接 受 了 适 当 的 培 训 并 胜 任 C 程 序 员 工<br />

作 。<br />

3.5 C++ 问 题<br />

C++ 不 同 于 C 语 言 , 本 文 档 的 范 围 不 包 含 它 , 也 不 试 图 讲 解 C++ 对 于 编 写 安 全 相 关 系 统<br />

的 适 合 性 与 否 。 然 而 对 于 C++ 编 译 器 和 代 码 的 使 用 方 面 应 该 给 出 以 下 说 明 。<br />

C++ 不 仅 仅 是 C 的 超 集 ( 即 增 加 多 余 的 C 特 性 )。 在 C 和 C++ 中 有 少 数 特 殊 构 造 具 有 不 同<br />

的 解 释 。 而 且 有 效 的 C 代 码 可 以 包 含 一 些 在 C++ 中 是 保 留 字 的 标 识 符 。 基 于 这 些 原 因 , 由 C<br />

7


写 成 的 符 合 ISO 标 准 的 代 码 在 C++ 编 译 器 中 可 能 不 会 编 译 成 其 在 C 编 译 器 中 的 结 果 。 因 此 本<br />

文 档 不 赞 成 使 用 C++ 编 译 器 编 译 C 代 码 。 如 果 为 了 实 用 性 原 因 必 须 使 用 C++ 编 译 器 编 译 C 代<br />

码 , 那 么 首 先 必 须 完 全 理 解 两 种 语 言 的 不 同 之 处 。<br />

然 而 鼓 励 使 用 附 加 的 编 译 器 , 如 静 态 检 查 工 具 。 基 于 此 目 的 , 在 不 关 心 可 执 行 代 码 的 地<br />

方 , 可 以 使 用 C++ 编 译 器 , 而 且 这 也 确 实 能 提 供 好 处 , 因 为 它 具 有 比 C 更 强 的 类 型 检 测 能 力 。<br />

如 果 一 个 做 为 “C++” 销 售 的 编 译 器 严 格 地 符 合 了 ISO C 的 操 作 模 式 , 那 么 它 就 相 当 于 一<br />

个 C 编 译 器 , 并 可 以 以 C 编 译 器 的 形 式 使 用 ( 只 对 于 C 代 码 )。 对 于 其 他 任 何 包 含 了 适 应 ISO<br />

C 编 译 器 的 功 能 部 分 的 工 具 而 言 , 这 也 是 成 立 的 。<br />

C++ 注 释 不 应 用 在 C 代 码 中 。 尽 管 C 编 译 器 支 持 这 种 形 式 的 注 释 ( 由 // 表 示 的 ), 它 们 也<br />

不 是 ISO 标 准 C 的 一 部 分 ( 见 规 则 2.2)。<br />

3.6 自 动 产 生 代 码 的 问 题<br />

如 果 要 使 用 代 码 自 动 产 生 工 具 , 那 么 有 必 要 选 择 一 个 合 适 的 工 具 并 采 取 有 效 性 验 证 的 手<br />

段 。 建 议 遵 循 本 文 档 的 要 求 , 它 可 以 提 供 评 估 工 具 的 准 则 , 除 此 之 外 在 这 方 面 没 有 更 多 的 指<br />

南 , 读 者 可 以 参 考 HSE 的 COTS 建 议 [10]。<br />

为 了 进 行 有 效 性 验 证 , 对 待 自 动 产 生 代 码 的 方 式 必 须 与 对 待 手 工 产 生 代 码 的 方 式 相 同 ( 见<br />

<strong>MISRA</strong> 指 南 [9] 3.1.3,Planning for V&V)。<br />

8


4 使 用 <strong>MISRA</strong>-C<br />

4.1 软 件 工 程 环 境<br />

使 用 编 程 语 言 产 生 源 代 码 只 是 软 件 开 发 过 程 中 的 一 个 活 动 。 如 果 只 在 这 样 的 活 动 中 坚 持<br />

最 佳 实 践 而 不 考 虑 其 他 开 发 问 题 , 只 能 带 来 有 限 的 价 值 。 在 安 全 相 关 系 统 的 开 发 中 尤 其 如 此 。<br />

这 些 问 题 在 <strong>MISRA</strong> 指 南 [9] 中 都 提 到 了 , 比 如 :<br />

• 文 档 化 开 发 过 程<br />

• 能 够 满 足 ISO 9001/ISO 90003/Tick IT [11,12,13] 标 准 的 质 量 体 系<br />

• 项 目 管 理<br />

• 配 置 管 理<br />

• 风 险 分 析 (Hazard Analysis)<br />

• 需 求<br />

• 设 计<br />

• 编 码<br />

• 确 认 (Verificaiton)<br />

• 有 效 性 验 证 (Validation)<br />

软 件 开 发 者 有 必 要 证 明 他 们 整 个 的 开 发 过 程 对 其 所 开 发 的 系 统 来 说 是 合 适 的 。 这 样 的 声<br />

明 只 有 当 执 行 完 确 定 系 统 安 全 集 成 度 的 风 险 分 析 活 动 后 才 算 完 成 。<br />

4.2 编 程 语 言 和 编 码 环 境<br />

在 软 件 开 发 过 程 的 编 码 阶 段 , 语 言 子 集 只 是 许 多 方 面 之 一 , 而 如 果 不 考 虑 其 他 开 发 问 题 ,<br />

只 在 这 一 方 面 中 坚 持 最 佳 实 践 , 只 能 带 来 有 限 的 价 值 。 紧 接 语 言 的 选 择 之 后 的 , 其 他 关 键 问<br />

题 是 :<br />

• 培 训<br />

• 风 格 指 南 (Style guide)<br />

• 编 译 器 选 择 和 有 效 性 验 证<br />

• 检 查 工 具 的 验 证<br />

• 度 量<br />

• 测 试 覆 盖 率<br />

在 这 些 问 题 上 做 出 的 所 有 选 择 及 其 原 因 都 要 记 录 成 文 档 , 并 对 任 何 执 行 的 活 动 保 持 适 当<br />

的 记 录 。 然 后 , 在 需 要 时 这 样 的 文 档 可 以 包 含 进 安 全 性 声 明 中 。<br />

4.2.1 培 训 (Training)<br />

为 了 确 保 C 代 码 编 写 者 具 有 合 适 的 熟 练 程 度 和 能 力 , 应 该 提 供 正 规 训 练 :<br />

• 嵌 入 式 应 用 中 C 编 程 语 言 的 使 用<br />

9


• 高 度 集 成 的 和 安 全 相 关 的 系 统 中 C 编 程 语 言 的 使 用<br />

• 用 于 强 制 遵 循 子 集 的 静 态 检 查 工 具 的 使 用<br />

4.2.2 风 格 指 南 (Style guide)<br />

除 了 采 用 语 言 子 集 外 , 一 个 组 织 应 该 有 其 自 己 的 实 验 室 内 的 编 程 风 格 。 这 包 含 那 些 不 直<br />

接 影 响 代 码 正 确 性 但 定 义 了 代 码 呈 现 形 式 的 “ 实 验 室 风 格 ”(house style) 的 问 题 。 这 些 问 题 是<br />

主 观 的 。 风 格 指 南 涉 及 的 典 型 问 题 包 括 :<br />

• 代 码 布 局 和 缩 进 的 使 用<br />

• 大 括 号 “{}” 和 结 构 块 的 布 局<br />

• 语 句 的 复 杂 性<br />

• 命 名 规 范<br />

• 注 释 语 句 的 使 用<br />

• 公 司 名 称 、 版 权 提 示 和 其 他 标 准 文 件 头 信 息 的 包 含<br />

正 如 风 格 指 南 的 某 些 内 容 是 建 议 性 的 , 某 些 内 容 也 是 强 制 性 的 。 然 而 , 对 风 格 的 强 制 不<br />

在 本 文 档 所 讨 论 的 范 围 之 内 。<br />

关 于 风 格 的 更 多 信 息 参 见 [14]。<br />

4.2.3 工 具 选 择 和 有 效 性 验 证<br />

在 选 择 编 译 器 ( 可 以 理 解 为 包 括 链 接 器 ) 时 , 尽 可 能 地 要 使 用 适 应 ISO C 的 编 译 器 。 如<br />

果 语 言 的 使 用 依 赖 于 “ 实 现 定 义 ”(implementation-defined) 的 特 性 ( 如 ISO 标 准 [2] 的 Annex G.3<br />

中 所 确 认 的 ), 那 么 开 发 者 必 须 检 测 编 译 器 以 确 认 其 实 现 与 编 译 器 编 写 者 所 声 明 的 一 致 。Annex<br />

G 的 更 多 解 释 见 5.5.2 节 。<br />

在 选 择 静 态 检 查 工 具 时 , 很 明 显 地 需 要 该 工 具 尽 可 能 多 地 强 制 遵 循 本 文 档 的 规 则 。 为 了<br />

这 个 目 标 , 重 要 的 是 工 具 能 在 整 个 程 序 范 围 内 进 行 检 查 , 而 不 是 单 单 一 个 源 文 件 。 另 外 , 如<br />

果 一 个 检 查 工 具 能 执 行 超 出 本 文 档 要 求 之 外 的 检 查 , 建 议 进 行 额 外 的 检 查 。<br />

编 译 器 和 静 态 检 查 工 具 通 常 被 视 作 “ 可 信 的 ”(trusted) 过 程 。 这 意 味 着 对 工 具 的 输 出 具<br />

有 相 当 程 度 的 信 任 , 因 此 程 序 员 必 须 要 确 保 这 样 的 信 任 不 是 一 种 错 信 。 理 想 的 是 , 这 种 信 任<br />

应 该 由 工 具 的 供 应 商 通 过 运 行 合 适 的 有 效 性 测 试 来 达 到 。 需 要 说 明 的 是 , 虽 然 能 采 用 有 效 性<br />

验 证 的 方 法 来 为 一 个 嵌 入 式 目 标 测 试 编 译 器 , 但 在 本 文 档 发 布 时 还 没 有 这 样 的 形 式 化 验 证 机<br />

制 。 另 外 , 这 些 工 具 应 该 被 开 发 成 能 够 满 足 ISO 9001/ISO 90003[11,12,13] 的 质 量 体 系 。<br />

工 具 的 供 应 商 应 该 能 提 供 确 认 和 有 效 性 验 证 活 动 的 记 录 以 及 软 件 的 可 控 开 发 过 程 的 变 更<br />

记 录 。 供 应 商 应 该 具 有 下 面 的 机 制 :<br />

• 记 录 由 用 户 报 告 的 缺 陷<br />

• 对 现 有 客 户 通 告 已 知 的 缺 陷<br />

• 在 未 来 的 发 布 中 改 正 缺 陷<br />

现 有 客 户 群 的 规 模 以 及 对 前 6 到 12 个 月 报 告 的 缺 陷 的 观 察 能 够 说 明 工 具 的 稳 定 性 。<br />

通 常 不 大 可 能 从 供 应 商 那 里 得 到 这 等 层 次 的 保 证 , 在 这 些 情 况 下 开 发 者 的 职 责 是 确 保 工<br />

具 具 有 足 够 的 质 量 。<br />

开 发 者 可 以 采 用 的 增 强 工 具 信 心 的 可 能 手 段 是 :<br />

• 执 行 某 种 形 式 的 文 档 化 验 证 测 试<br />

• 评 估 工 具 供 应 商 的 软 件 开 发 过 程<br />

10


• 检 阅 工 具 迄 今 为 止 的 性 能<br />

可 以 通 过 创 建 代 码 例 子 在 工 具 上 运 行 来 执 行 有 效 性 验 证 。 对 编 译 器 来 说 , 它 可 以 由 前 面<br />

应 用 中 已 知 的 良 好 代 码 组 成 。 对 静 态 检 查 工 具 , 应 该 写 一 套 代 码 文 件 , 每 个 文 件 打 破 子 集 中<br />

的 一 条 规 则 , 并 且 所 有 文 件 在 一 起 要 覆 盖 尽 可 能 多 的 规 则 。 然 后 , 静 态 检 查 工 具 为 每 个 测 试<br />

文 件 发 现 不 适 应 的 代 码 。 尽 管 这 样 的 测 试 是 受 限 的 , 它 们 也 将 确 立 基 本 层 次 上 的 工 具 行 为 。<br />

需 要 说 明 的 是 , 在 做 编 译 器 的 有 效 性 验 证 时 , 要 使 用 与 编 译 产 品 代 码 时 相 同 的 编 译 器 选<br />

项 、 链 接 器 选 项 和 源 文 件 库 版 本 。<br />

4.2.4 源 代 码 复 杂 度<br />

强 烈 建 议 使 用 源 代 码 的 复 杂 性 度 量 。 这 可 以 防 止 编 写 出 难 以 控 制 和 难 以 测 试 的 代 码 。 同<br />

样 高 度 建 议 使 用 工 具 进 行 数 据 的 搜 集 工 作 。 许 多 可 以 用 于 强 制 遵 循 子 集 的 工 具 同 样 具 有 产 生<br />

度 量 数 据 的 能 力 。<br />

详 细 的 源 代 码 度 量 参 见 “Software Metrics: A Rigorous and Practical Approach”(Fenton 和<br />

Pfleeger)[15], 以 及 <strong>MISRA</strong> 关 于 软 件 度 量 的 报 告 [16]。<br />

4.2.5 测 试 覆 盖 率<br />

在 软 件 设 计 和 编 写 之 前 , 应 该 定 义 好 它 期 望 达 到 的 语 句 覆 盖 率 。 代 码 的 设 计 和 编 写 应 该<br />

能 使 其 在 测 试 中 达 到 很 高 的 语 句 覆 盖 率 。 在 机 械 、 电 气 和 电 子 领 域 , 这 个 概 念 有 个 术 语 叫<br />

“Design For Test”(DFT)。 在 编 写 代 码 的 过 程 中 就 应 该 考 虑 这 个 问 题 , 因 为 达 到 高 语 句 覆 盖<br />

的 能 力 是 源 代 码 的 新 兴 属 性 。<br />

使 用 子 集 , 它 减 少 了 定 义 实 现 的 属 性 的 数 量 和 增 加 了 模 块 接 口 兼 容 性 , 能 产 生 可 以 进 行<br />

较 大 规 模 集 成 和 测 试 的 软 件 。<br />

折 中 考 虑 以 下 的 度 量 可 以 促 进 高 语 句 覆 盖 率 的 实 现 :<br />

• 代 码 规 模<br />

• 圈 复 杂 度<br />

• 静 态 路 径 数 目<br />

使 用 计 划 好 的 方 法 , 在 软 件 设 计 、 语 言 使 用 和 DFT 上 的 花 费 可 以 由 测 试 阶 段 中 要 达 到 高<br />

语 句 覆 盖 率 所 需 时 间 的 缩 减 来 补 偿 。 见 [16,17]。<br />

4.3 采 用 子 集 (subset)<br />

为 了 开 发 符 合 子 集 要 求 的 代 码 , 需 要 遵 循 以 下 步 骤 :<br />

• 产 生 一 个 符 合 性 矩 阵 (compliance matrix), 声 明 是 如 何 强 制 每 个 规 则 的<br />

• 产 生 一 个 背 离 (deviation) 过 程<br />

• 在 质 量 管 理 系 统 中 统 一 工 作 实 践 的 形 式<br />

4.3.1 符 合 性 矩 阵 (Compliance matrix)<br />

为 了 确 保 所 编 写 的 代 码 符 合 子 集 , 有 必 要 进 行 适 当 的 测 量 , 检 查 它 没 有 打 破 规 则 。 要 做<br />

到 这 一 点 最 有 效 的 手 段 是 , 使 用 一 个 或 多 个 静 态 检 查 工 具 。 如 果 工 具 不 能 检 查 某 条 规 则 , 那<br />

么 就 必 须 进 行 人 工 检 查 。<br />

为 了 确 保 所 有 的 规 则 都 覆 盖 到 了 , 就 需 要 产 生 一 个 符 合 性 矩 阵 , 矩 阵 中 列 出 每 条 规 则 并<br />

说 明 它 是 如 何 被 检 查 的 。 例 如 表 1。 见 附 录 A 中 的 规 则 列 表 , 它 可 以 帮 助 产 生 完 整 的 符 合 性 矩<br />

阵 。<br />

11


Rule No. Comiler1 Compiler2 Checking Tool 1 Checking Tool 2 Manual Review<br />

1.1 Warning 347<br />

1.2 Error 25<br />

1.3 Message 38<br />

1.4 Warning 97<br />

1.5 Proc x.y<br />

Table 1: Example compliance matrix<br />

如 果 开 发 者 具 有 其 他 的 本 地 约 束 , 也 可 以 加 入 到 符 合 性 矩 阵 中 。 在 忽 略 特 定 约 束 的 地 方 ,<br />

要 给 出 完 整 的 说 明 。 这 些 说 明 必 须 是 能 被 C 语 言 专 家 和 管 理 者 一 同 承 认 的 。<br />

4.3.2 背 离 过 程 (Deviation procedure)<br />

要 知 道 在 某 些 情 况 下 需 要 背 离 本 文 档 给 出 的 规 则 。 例 如 , 与 微 处 理 器 硬 件 接 口 的 源 代 码<br />

会 不 可 避 免 地 需 要 使 用 适 当 的 语 言 扩 展 。<br />

为 了 具 有 权 威 性 , 有 必 要 使 用 一 个 正 规 的 过 程 来 认 可 这 些 背 离 , 而 不 是 依 靠 一 个 个 体 的<br />

程 序 员 随 意 背 离 规 则 的 判 断 力 。 背 离 的 使 用 必 须 在 必 要 性 和 安 全 性 上 被 声 明 为 是 正 确 的 。 由<br />

于 本 文 档 不 打 算 给 出 每 条 规 则 的 重 要 等 级 , 因 此 如 果 说 某 些 条 款 是 比 其 他 条 款 更 为 关 键 也 是<br />

可 以 接 受 的 。 这 将 反 映 在 背 离 的 过 程 中 , 如 果 对 于 更 为 严 重 的 背 离 , 需 要 更 强 的 技 术 能 力 以<br />

评 估 即 将 招 致 的 风 险 , 需 要 更 高 的 管 理 以 接 受 这 种 增 加 的 风 险 。 如 果 存 在 正 规 化 的 质 量 管 理<br />

系 统 , 那 么 背 离 过 程 应 该 是 该 系 统 的 一 部 分 。<br />

背 离 的 发 生 可 以 是 针 对 某 一 特 殊 实 例 , 即 在 单 一 文 件 中 一 次 性 出 现 的 事 物 , 或 者 是 针 对<br />

某 一 类 环 境 , 即 一 特 定 环 境 中 特 定 结 构 的 系 统 级 使 用 , 如 使 用 特 定 的 语 言 扩 展 实 现 处 理 串 口<br />

通 讯 的 文 件 I/O 操 作 。<br />

严 格 遵 循 所 有 规 则 是 不 大 可 能 的 , 而 且 在 实 际 中 , 与 个 体 情 形 有 关 的 背 离 是 可 以 容 许 的 。<br />

背 离 的 种 类 有 两 种 :<br />

• 项 目 背 离 (Project Deviation): 项 目 背 离 定 义 为 可 允 许 的 对 规 则 要 求 的 放 宽 , 以 应 用<br />

在 特 殊 环 境 中 。 实 际 上 , 项 目 背 离 在 项 目 开 始 时 总 是 可 以 的 。<br />

• 特 定 背 离 (Specific Deviation): 特 定 背 离 定 义 为 在 某 个 文 件 中 对 某 规 则 的 背 离 , 典 型<br />

地 由 对 环 境 的 响 应 给 出 。 特 定 背 离 发 生 在 开 发 过 程 中 。<br />

项 目 背 离 需 要 正 规 地 检 查 回 顾 , 这 样 的 检 查 应 该 是 形 式 化 背 离 过 程 的 一 部 分 。<br />

一 些 需 要 打 破 规 则 的 环 境 关 心 的 是 输 入 / 输 出 的 操 作 。 建 议 软 件 的 设 计 要 使 得 对 输 入 / 输 出<br />

的 关 注 同 软 件 的 其 他 部 分 隔 离 开 来 。 在 代 码 的 输 入 / 输 出 部 分 中 要 尽 可 能 地 限 制 项 目 背 离 。 服<br />

从 于 项 目 背 离 的 代 码 应 该 标 记 出 来 。<br />

本 文 档 的 目 标 是 要 仔 细 考 虑 这 些 问 题 并 采 取 可 靠 的 手 段 以 避 免 这 些 问 题 。 不 应 该 使 用 背<br />

离 过 程 去 破 坏 这 样 的 思 想 。 在 遵 循 本 文 档 的 规 则 时 , 开 发 者 同 时 也 利 用 了 <strong>MISRA</strong> 在 理 解 这 些<br />

问 题 时 所 做 出 的 努 力 。 如 果 要 背 离 规 则 , 那 么 开 发 者 就 必 须 要 理 解 问 题 本 身 。 所 有 的 背 离 ,<br />

包 括 标 准 的 和 特 定 的 , 都 应 该 记 录 成 文 档 。<br />

例 如 , 如 果 预 先 知 道 很 难 遵 循 某 一 规 则 , 软 件 开 发 者 应 该 提 交 一 份 项 目 背 离 请 求 (Project<br />

Deviation Request) 并 在 开 始 编 程 之 前 征 得 客 户 方 的 同 意 。<br />

项 目 背 离 请 求 应 该 包 含 如 下 内 容 :<br />

• 背 离 的 细 节 , 即 被 背 离 的 规 则<br />

• 需 要 产 生 背 离 的 环 境<br />

• 由 背 离 产 生 的 潜 在 后 果<br />

• 对 背 离 的 正 确 性 声 明<br />

12


• 声 明 如 何 保 障 安 全 性<br />

如 果 在 开 发 过 程 期 间 或 结 尾 出 现 了 对 背 离 的 需 求 , 软 件 开 发 者 应 该 提 交 一 份 特 定 背 离 请<br />

求 (Specfic Deviation Request)。<br />

特 定 背 离 请 求 应 该 包 含 如 下 内 容 :<br />

• 背 离 的 细 节 , 即 被 背 离 的 规 则<br />

• 由 背 离 产 生 的 潜 在 后 果<br />

• 对 背 离 的 正 确 性 声 明<br />

• 声 明 如 何 保 障 安 全 性<br />

这 些 过 程 的 实 现 细 节 留 给 用 户 决 定 。<br />

4.3.3 质 量 体 系 中 的 形 式 化<br />

子 集 、 静 态 检 查 工 具 和 背 离 过 程 的 使 用 应 该 由 形 式 化 的 文 档 在 质 量 管 理 体 系 中 做 出 描 述 。<br />

然 后 它 们 要 经 过 与 质 量 体 系 相 关 的 内 部 和 外 部 审 查 , 这 将 促 进 它 们 的 一 致 性 使 用 。<br />

4.3.4 引 入 子 集<br />

如 果 一 个 组 织 已 经 具 有 C 代 码 编 程 环 境 , 那 么 建 议 引 入 本 文 档 规 则 ( 见 Hatton[3] 的 第 五<br />

章 )。 实 现 本 文 档 的 所 有 内 容 可 能 需 要 1 到 2 年 的 时 间 。<br />

如 果 某 产 品 包 含 了 在 使 用 子 集 前 编 写 的 代 码 , 重 写 这 些 代 码 以 适 应 子 集 可 能 是 不 现 实 的 。<br />

在 这 种 情 况 下 , 开 发 者 必 须 决 定 管 理 引 入 子 集 的 策 略 ( 例 如 : 所 有 新 模 块 要 写 成 符 合 子 集 的<br />

方 式 , 而 对 于 已 存 在 的 模 块 , 如 果 它 们 要 做 出 超 过 非 注 释 语 句 30% 的 更 改 , 那 么 就 要 重 写 成<br />

符 合 子 集 的 形 式 )。<br />

4.4 符 合 性 声 明 (Claiming compliance)<br />

只 能 为 产 品 而 不 能 为 组 织 声 明 符 合 性 。<br />

在 为 一 个 产 品 声 明 <strong>MISRA</strong>-C 文 档 的 符 合 性 时 , 开 发 者 的 意 思 是 在 说 , 存 在 着 体 现 下 列 内<br />

容 的 依 据 :<br />

• 完 成 了 符 合 性 矩 阵 , 它 显 示 出 如 何 强 制 符 合 性 的<br />

• 产 品 中 所 有 C 代 码 与 本 文 档 的 规 则 是 一 致 的 , 或 者 遵 循 了 对 文 档 规 则 的 背 离<br />

• 维 持 了 没 有 遵 循 的 所 有 规 则 实 例 列 表 , 对 每 个 实 例 来 说 ,……<br />

• 4.2 节 中 提 到 的 问 题 已 经 解 决 了<br />

4.5 持 续 改 进<br />

对 本 文 档 规 则 的 遵 循 只 是 持 续 改 进 过 程 的 第 一 步 。 用 户 必 须 要 知 道 其 他 主 题 内 容 ( 见 参<br />

考 ), 并 且 要 主 动 使 用 度 量 寻 求 开 发 过 程 的 改 进 。<br />

13


5 规 则 简 介<br />

这 一 节 描 述 文 档 第 6 节 中 规 则 的 表 达 方 式 。 是 文 档 主 要 内 容 的 简 单 介 绍 。<br />

5.1 规 则 分 类<br />

第 6 节 中 的 每 条 规 则 都 被 分 类 成 “ 强 制 ”(required) 或 “ 建 议 ”(advisory), 在 后 面 描 述 。<br />

在 这 个 基 本 分 类 之 外 , 文 档 不 打 算 给 出 每 条 规 则 的 重 要 等 级 。 所 有 强 制 的 规 则 具 有 同 等 重 要<br />

性 , 所 有 建 议 的 规 则 也 如 此 。 文 档 中 对 某 一 项 的 忽 略 也 不 表 明 它 的 重 要 性 较 低 。<br />

“ 强 制 ” 和 “ 建 议 ” 的 含 义 如 下 :<br />

5.1.1 强 制 规 则<br />

这 是 对 程 序 员 的 强 制 要 求 。 文 档 中 共 有 121 条 “ 强 制 ” 规 则 。 声 明 遵 循 本 文 档 的 C 代 码<br />

应 该 适 合 每 条 强 制 规 则 , 如 果 不 是 , 就 需 要 具 有 形 式 化 的 背 离 , 见 4.3.2 节 。<br />

5.1.2 建 议 规 则<br />

这 些 要 求 程 序 员 在 通 常 情 况 下 都 要 遵 守 。 然 而 它 们 不 象 强 制 规 则 那 样 带 有 强 迫 性 质 。 文<br />

档 中 共 有 20 条 “ 建 议 ” 规 则 。 要 说 明 的 是 ,“ 建 议 ” 不 意 味 着 可 以 忽 略 这 些 规 则 , 而 是 应 该<br />

遵 守 直 至 合 理 的 实 现 。 对 建 议 规 则 来 说 不 需 要 形 式 化 的 背 离 , 但 如 果 背 离 是 适 当 的 , 也 可 以<br />

产 生 。<br />

5.2 规 则 的 组 织<br />

规 则 被 组 织 在 C 语 言 的 不 同 主 题 下 。 但 不 可 避 免 地 会 有 一 些 重 叠 , 一 条 规 则 可 能 会 同 一<br />

些 主 题 相 关 。 这 种 情 况 下 , 规 则 被 安 排 在 最 具 相 关 性 的 主 题 下 。<br />

5.3 规 则 的 冗 余<br />

本 文 档 中 存 在 少 数 这 样 的 情 况 , 某 规 则 的 给 出 针 对 某 一 语 言 特 性 , 该 语 言 特 性 在 某 处 是<br />

禁 止 的 而 在 他 处 却 是 建 议 使 用 的 。 这 是 有 意 的 。 用 户 可 能 要 通 过 以 下 两 种 方 式 选 用 该 语 言 特<br />

性 , 或 者 是 产 生 对 某 强 制 规 则 的 背 离 , 或 者 是 选 择 不 遵 循 某 条 建 议 规 则 。 这 种 情 况 下 , 第 二<br />

条 限 制 语 言 特 性 使 用 的 规 则 成 为 相 关 的 规 则 。<br />

5.4 规 则 的 形 式<br />

本 文 档 中 的 个 体 规 则 书 写 形 式 如 下 :<br />

规 则 < 序 号 > (< 类 别 >): < 规 则 文 本 ><br />

[< 原 始 参 考 >]<br />

各 内 容 如 下 :<br />

• < 序 号 >: 每 条 规 则 带 有 唯 一 的 序 号 。 序 号 的 前 缀 是 规 则 的 组 别 , 后 缀 是 在 规 则 组 中<br />

的 序 号 。<br />

14


• < 类 别 >: 或 者 是 “ 强 制 ”, 或 者 是 “ 建 议 ”, 见 5.1 节 中 的 解 释<br />

• < 规 则 文 本 >: 规 则 内 容<br />

• < 原 始 参 考 >: 指 示 了 产 生 本 条 款 或 本 组 条 款 的 可 应 用 的 主 要 来 源 。5.5 节 描 述 了 这 些<br />

参 考 的 重 要 性 以 及 到 原 始 材 料 的 连 接 。<br />

另 外 , 对 每 项 条 款 或 成 组 相 关 条 款 提 供 了 支 持 文 本 。 该 文 本 描 述 了 规 则 所 涉 及 的 基 本 问<br />

题 及 如 何 应 用 规 则 的 例 子 。 如 果 在 某 一 规 则 后 没 有 紧 跟 这 样 的 解 释 文 本 , 那 么 对 应 文 本 会 在<br />

一 组 规 则 后 找 到 , 这 段 文 本 适 应 于 其 前 所 有 规 则 。 类 似 地 , 一 组 规 则 后 的 原 始 参 考 适 用 于 整<br />

组 规 则 。<br />

支 持 文 本 不 是 做 为 相 关 语 言 特 性 的 指 南 , 我 们 假 设 读 者 已 经 具 有 关 于 语 言 的 工 作 经 验 。<br />

语 言 特 性 的 更 为 详 细 的 信 息 可 以 通 过 咨 询 相 关 的 语 言 标 准 或 其 他 C 语 言 参 考 书 来 获 得 。 如 果<br />

原 始 参 考 给 出 了 一 个 或 多 个 ISO 标 准 中 “Annex G” 条 款 , 那 么 ISO 标 准 中 提 出 的 原 始 问 题 将<br />

有 助 于 对 规 则 的 理 解 。<br />

在 代 码 段 中 , 下 列 已 经 typedef 定 义 的 类 型 假 设 为 ( 为 了 适 应 规 则 6.3):<br />

char_t<br />

uint8_t<br />

uin16_t<br />

uint32_t<br />

int8_t<br />

int16_t<br />

int32_t<br />

float32_t<br />

float64_t<br />

plain 8 bit character<br />

unsigned 8 bit integer<br />

unsigned 16 bit integer<br />

unsigned 32 bit integer<br />

signed 8 bit integer<br />

signed 16 bit integer<br />

signed 32 bit integer<br />

32 bit floating-point<br />

64 bit floating-point<br />

非 特 意 定 义 的 变 量 名 称 指 示 其 类 型 。 例 如 :<br />

uint8_t<br />

sint32_t<br />

u8a;<br />

s32a;<br />

5.5 理 解 原 始 参 考<br />

当 规 则 来 源 于 一 个 或 多 个 已 发 表 的 原 始 文 件 时 , 这 些 来 源 会 在 一 个 方 括 号 中 标 明 。 这 样<br />

做 有 两 个 目 的 。 首 先 , 读 者 可 以 咨 询 这 些 特 定 的 资 源 以 充 分 了 解 规 则 之 后 的 基 本 原 理 ( 比 如<br />

需 要 对 规 则 有 所 背 离 的 时 候 )。 其 次 , 考 虑 到 ISO 标 准 中 “Annex G” 提 到 的 问 题 , 这 些 资 源<br />

的 类 型 给 出 了 这 些 问 题 性 质 的 额 外 信 息 ( 见 5.5.2 节 )。<br />

下 面 给 出 连 接 这 些 资 源 的 关 键 字 及 相 关 解 释 。<br />

5.5.1 原 始 参 考 关 键 字<br />

Reference<br />

Source<br />

Annex G of ISO 9899 [2]<br />

Unspecified<br />

Undefined<br />

Implementation<br />

Locale<br />

Unspecified behavivour (G.1)<br />

Undefined behavivour (G.2)<br />

Implementation-defined behaviour (G.3)<br />

Locale-specific behaviour (G.4)<br />

15


Other<br />

<strong>MISRA</strong> Guidelines The <strong>MISRA</strong> Guidelines [9]<br />

K & R Kernighan and Ritchie [18]<br />

Koenig “C Traps and Pitfalls”,Koenig [19]<br />

IEC 61508 IEC 61508: 1998-2002 [20]<br />

参 考 后 面 出 现 数 字 时 , 它 们 具 有 如 下 含 义 :<br />

• ISO 9899 参 考 的 Annex G: 该 条 款 在 Annex 中 相 应 章 节 中 的 序 号 , 序 号 从 该 章 节 的<br />

开 始 处 计 算 。 所 以 ,[Locale 2] 代 表 标 准 中 G.4 节 的 第 二 条 款 。<br />

• 在 排 列 参 考 时 给 出 相 应 的 页 数 ( 除 非 另 外 声 明 )。<br />

5.5.2 理 解 Annex G 参 考<br />

如 果 规 则 是 基 于 ISO C 标 准 中 的 Annex G, 理 解 以 下 问 题 的 区 别 将 对 读 者 有 所 帮 助 , 即<br />

“unspecified”、“undefined”、“implementation-defined” 和 “locale-specific”。 这 里 给 出 简 单 的<br />

解 释 , 详 细 信 息 请 参 考 Hatton[3]。<br />

5.5.2.1 Unspecified<br />

这 些 是 必 须 成 功 编 译 的 语 言 结 构 , 但 关 于 结 构 的 行 为 , 编 译 器 的 编 写 者 有 某 些 自 由 。 例<br />

如 规 则 12.2 中 描 述 的 “ 运 算 次 序 ”。 这 样 的 问 题 有 22 个 。<br />

在 某 种 方 式 上 完 全 相 信 编 译 器 的 行 为 是 不 明 智 的 。 编 译 器 的 行 为 甚 至 不 会 在 所 有 可 能 的<br />

结 构 中 都 是 一 致 的 。<br />

5.5.2.2 Undefined<br />

这 些 是 本 质 的 编 程 错 误 , 但 编 译 器 的 编 写 者 不 一 定 为 此 给 出 错 误 信 息 。 相 应 的 例 子 是 无<br />

效 参 数 传 递 给 函 数 , 或 函 数 的 参 数 与 定 义 时 的 参 数 不 匹 配 。<br />

从 安 全 性 角 度 这 是 特 别 重 要 的 问 题 , 因 为 它 们 代 表 了 那 些 不 一 定 能 被 编 译 器 捕 捉 到 的 错<br />

误 。<br />

5.5.2.3 Implementation-defined<br />

这 有 些 类 似 于 “unspecified” 问 题 , 其 主 要 区 别 在 于 编 译 器 要 提 供 一 致 的 行 为 并 记 录 成 文<br />

档 。 换 句 话 说 , 不 同 的 编 译 器 之 间 功 能 可 能 会 有 不 同 , 使 得 代 码 不 具 有 可 移 植 性 , 但 在 任 一<br />

编 译 器 内 , 行 为 应 当 是 良 好 定 义 的 。 比 如 用 在 一 个 正 整 数 和 一 个 负 整 数 上 的 整 除 运 算 “/” 和<br />

求 模 运 算 符 “%”。 存 在 76 个 这 样 的 问 题 。<br />

从 安 全 性 角 度 , 假 如 编 译 器 完 全 地 记 录 了 它 的 方 法 并 坚 持 它 的 实 现 , 那 么 它 可 能 不 是 那<br />

样 至 关 重 要 。 尽 可 能 的 情 况 下 要 避 免 这 些 问 题 。<br />

5.5.2.4 Locale-specfic<br />

这 是 与 国 际 标 准 有 所 不 同 的 一 些 小 的 特 性 。 如 在 表 示 十 进 制 的 小 数 点 时 使 用 “,” 字 符 替<br />

代 “.” 字 符 。 有 6 个 这 样 的 问 题 。 本 文 档 没 有 涉 及 这 项 资 源 提 出 的 问 题 。<br />

16


5.6 规 则 的 范 围<br />

原 则 上 , 规 则 要 用 在 应 用 程 序 的 所 有 程 序 文 件 。 虽 然 多 数 规 则 可 以 用 在 单 独 的 文 件 中 ,<br />

规 则 1.1、1.2、1.3、1.4、2.1、3.6、5.1、5.3、5.4、5.5、5.6、5.7、8.4、8.8、8.9、8.10、12.2、<br />

12.4、14.1、14.2、16.2、16.4、17.2、18.1、18.2、18.3 和 21.1 必 须 要 用 在 所 有 文 件 中 。<br />

17


6 规 则<br />

6.1 环 境<br />

规 则 1.1( 强 制 ):<br />

所 有 代 码 都 必 须 遵 照 ISO 9899:1990 “Programming languages - C”,<br />

由 ISO/IEC 9899/COR1:1995,ISO/IEC 9899/AMD1:1995, 和 ISO/IEC<br />

9899/COR2:1996 修 订 。<br />

[<strong>MISRA</strong> Guidelines Table 3;IEC 61508 Part 7:Table C.1]<br />

这 些 方 针 建 立 在 ISO 9899:1990 [2] 之 上 , 它 是 由 ISO/IEC 9899/COR1:1995 [4],ISO/IEC<br />

9899/AMD1:1995 [5] 以 及 ISO/IEC 9899/COR2:1996 [6] 修 订 的 。 并 没 有 适 应 于 ISO 9899:1999<br />

[8] 标 准 版 本 的 声 明 , 本 文 档 中 任 何 提 及 “Standard C” 的 地 方 都 是 指 旧 有 的 ISO9899:1990 [2]<br />

标 准 。<br />

必 须 认 识 到 “ 背 离 ”( 描 述 见 4.3.2 节 ) 的 提 出 是 必 要 的 , 这 能 允 许 一 定 的 语 言 扩 展 , 比<br />

如 对 硬 件 特 性 的 支 持 。<br />

当 ISO 9899:1990 5.2.4 [2] 中 指 定 的 环 境 限 制 超 出 了 范 围 , 就 需 要 提 出 “ 背 离 ”, 除 了 后<br />

面 的 规 则 5.1。<br />

规 则 1.2( 强 制 ): 不 能 有 对 未 定 义 行 为 或 未 指 定 行 为 的 依 赖 性 。<br />

这 项 规 则 要 求 任 何 对 未 定 义 行 为 或 未 指 定 行 为 的 依 赖 , 除 非 在 其 他 规 则 中 做 了 特 殊 说 明 ,<br />

都 应 该 避 免 。 如 果 其 他 某 项 规 则 中 声 明 了 某 个 特 殊 行 为 , 那 么 就 只 有 这 项 特 定 规 则 在 其 需 要<br />

时 给 出 背 离 性 。 这 些 问 题 的 完 整 列 表 详 见 ISO 9899:1990 附 录 G [2]。<br />

规 则 1.3( 强 制 ):<br />

多 个 编 译 器 和 / 或 语 言 只 能 在 为 语 言 / 编 译 器 / 汇 编 器 所 适 合 的 目 标 代 码<br />

定 义 了 通 用 接 口 标 准 时 使 用 。<br />

[ 未 指 定 11]<br />

如 果 一 个 模 块 是 以 非 C 语 言 实 现 的 或 是 以 不 同 的 C 编 译 器 编 译 的 , 那 么 必 须 要 保 证 该 模<br />

块 能 够 正 确 地 同 其 他 模 块 集 成 。C 语 言 行 为 的 某 些 特 征 依 赖 于 编 译 器 , 于 是 这 些 行 为 必 须 能 够<br />

为 使 用 的 编 译 器 所 理 解 。 例 如 : 栈 的 使 用 、 参 数 的 传 递 和 数 据 值 的 存 储 方 式 ( 长 度 、 排 列 、<br />

别 名 、 覆 盖 , 等 等 )。<br />

规 则 1.4( 强 制 ):<br />

编 译 器 / 链 接 器 要 确 保 31 个 有 效 字 符 和 大 小 写 敏 感 能 被 外 部 标 识 符 支<br />

持 。<br />

[ 未 定 义 7; 实 现 5、6]<br />

ISO 标 准 要 求 外 部 标 识 符 的 头 6 个 字 符 是 截 然 不 同 的 。 然 而 由 于 大 多 数 编 译 器 / 链 接 器 允<br />

许 至 少 31 个 有 效 字 符 ( 如 同 内 部 标 识 符 ), 因 此 对 这 样 严 格 而 并 不 具 有 帮 助 性 的 限 制 的 适 应<br />

性 被 认 为 是 不 必 要 的 。<br />

必 须 检 查 编 译 器 / 链 接 器 具 有 这 种 特 性 , 如 果 编 译 器 / 链 接 器 不 能 满 足 这 种 限 制 , 就 使 用 编<br />

译 器 本 身 的 约 束 。<br />

规 则 1.5( 建 议 ):<br />

浮 点 应 用 应 该 适 应 于 已 定 义 的 浮 点 标 准<br />

浮 点 运 算 会 带 来 许 多 问 题 , 一 些 问 题 ( 而 不 是 全 部 ) 可 以 通 过 适 应 已 定 义 的 标 准 来 克 服 。<br />

其 中 一 个 合 适 的 标 准 是 ANSI/IEEE Std 754 [21]。<br />

同 规 则 6.3 相 一 致 , 浮 点 类 型 的 定 义 提 供 了 一 个 注 释 所 用 浮 点 标 准 的 机 会 , 如 :<br />

/* IEEE 754 single-precision floating-point */<br />

18


typedef float float32_t;<br />

6.2 语 言 扩 展<br />

规 则 2.1( 强 制 ): 汇 编 语 言 应 该 被 封 装 并 隔 离 。<br />

[ 未 指 定 11]<br />

在 需 要 使 用 汇 编 指 令 的 地 方 , 建 议 以 如 下 方 式 封 装 并 隔 离 这 些 指 令 :(a) 汇 编 函 数 、(b) C<br />

函 数 、(c) 宏 。<br />

出 于 效 率 的 考 虑 , 有 时 必 须 要 嵌 入 一 些 简 单 的 汇 编 指 令 , 如 开 关 中 断 。 如 果 不 管 出 于 什<br />

么 原 因 需 要 这 样 做 , 那 么 最 好 使 用 宏 来 完 成 。<br />

需 要 注 意 的 是 , 内 嵌 的 汇 编 语 言 的 使 用 是 对 标 准 C 的 扩 展 , 因 此 也 需 要 提 出 对 规 则 1.1<br />

的 背 离 。<br />

#define NOP asm (“<br />

NOP”);<br />

规 则 2.2( 强 制 ): 源 代 码 应 该 使 用 /*…*/ 类 型 的 注 释 。<br />

这 排 除 了 如 // 这 样 C99 类 型 的 注 释 和 C++ 类 型 的 注 释 , 因 为 它 在 C90 中 是 不 允 许 的 。 许<br />

多 编 译 器 支 持 // 类 型 的 注 释 以 做 为 对 C90 的 扩 展 。 预 处 理 指 令 ( 如 #define) 中 // 的 使 用 可<br />

以 改 变 ,/*…*/ 和 // 的 混 合 使 用 也 是 不 一 致 的 。 这 不 仅 是 类 型 问 题 , 因 为 不 同 的 编 译 器 ( 在 C99<br />

之 前 ) 可 能 会 有 不 同 的 行 为 。<br />

规 则 2.3( 强 制 ): 字 符 序 列 /* 不 应 出 现 在 注 释 中 。<br />

C 不 支 持 注 释 的 嵌 套 , 尽 管 一 些 编 译 器 支 持 它 以 做 为 语 言 扩 展 。 一 段 注 释 以 /* 开 头 , 直 到<br />

第 一 个 */ 为 止 , 在 这 当 中 出 现 的 任 何 /* 都 违 反 了 本 规 则 。 考 虑 如 下 代 码 段 :<br />

/* some comment, end comment marker accidentally omitted<br />

<br />

Perform_Critical_Safety_Function (X);<br />

/* this comment is not compliant */<br />

在 检 查 包 含 函 数 调 用 的 页 中 , 假 设 它 是 可 执 行 代 码 。<br />

因 为 可 能 会 省 略 掉 注 释 的 结 束 标 记 , 那 么 对 安 全 关 键 函 数 的 调 用 将 不 会 被 执 行 。<br />

规 则 2.4( 建 议 ):<br />

代 码 段 不 应 被 “ 注 释 掉 ”(comment out)。<br />

当 源 代 码 段 不 需 要 被 编 译 时 , 应 该 使 用 条 件 编 译 来 完 成 ( 如 带 有 注 释 的 #if 或 #ifdef 结 构 )。<br />

为 这 种 目 的 使 用 注 释 的 开 始 和 结 束 标 记 是 危 险 的 , 因 为 C 不 支 持 嵌 套 的 注 释 , 而 且 已 经 存 在<br />

于 代 码 段 中 的 任 何 注 释 将 影 响 执 行 的 结 果 。<br />

6.3 文 档<br />

规 则 3.1( 强 制 ): 所 有 实 现 定 义 (implementation-defined) 的 行 为 的 使 用 都 应 该 文 档 化 。<br />

本 规 则 要 求 , 任 何 对 实 现 定 义 的 行 为 的 依 赖 —— 这 些 行 为 在 其 他 规 则 中 没 有 特 别 说 明 的<br />

—— 都 应 该 写 成 文 档 , 例 如 对 编 译 器 文 档 的 参 考 。 如 果 一 个 特 定 的 行 为 在 其 他 规 则 中 被 显 式<br />

说 明 了 , 那 么 只 有 那 项 规 则 在 其 需 要 时 给 出 背 离 。 完 整 问 题 的 描 述 详 见 ISO 9899:1990 附 录 G<br />

[2]。<br />

规 则 3.2( 强 制 ): 字 符 集 和 相 应 的 编 码 应 该 文 档 化 。<br />

例 如 ,ISO 10646 [22] 定 义 了 字 符 集 映 射 到 数 字 值 的 国 际 标 准 。 出 于 可 移 植 性 的 考 虑 , 字<br />

符 常 量 和 字 符 串 只 能 包 含 映 射 到 已 经 文 档 化 的 子 集 中 的 字 符 。<br />

19


规 则 3.3( 建 议 ): 应 该 确 定 、 文 档 化 和 重 视 所 选 编 译 器 中 整 数 除 法 的 实 现 。<br />

[ 实 现 18]<br />

当 两 个 有 符 号 整 型 数 做 除 法 时 ,ISO 兼 容 的 编 译 器 的 运 算 可 能 会 为 正 或 为 负 。 首 先 , 它 可<br />

能 以 负 余 数 向 上 四 舍 五 入 ( 如 ,-5/3 = -1, 余 数 为 -2), 或 者 可 能 以 正 余 数 向 下 四 舍 五 入 ( 如 ,<br />

-5/3 = -2, 余 数 为 +1)。 重 要 的 是 要 确 定 这 两 种 运 算 中 编 译 器 实 现 的 是 哪 一 种 , 并 以 文 档 方 式<br />

提 供 给 编 程 人 员 , 特 别 是 第 二 种 情 况 ( 通 常 这 种 情 况 比 较 少 )。<br />

规 则 3.4( 强 制 ): 所 有 #pragma 指 令 的 使 用 应 该 文 档 化 并 给 出 良 好 解 释 。<br />

[ 实 现 40]<br />

这 项 规 则 为 本 文 档 的 使 用 者 提 供 了 产 生 其 应 用 中 使 用 的 任 何 pragma 的 要 求 。 每 个 pragma<br />

的 含 义 要 写 成 文 档 , 文 档 中 应 当 包 含 完 全 可 理 解 的 对 pragma 行 为 及 其 在 应 用 中 之 含 义 的 充 分<br />

描 述 。<br />

应 当 尽 量 减 少 任 何 pragma 的 使 用 , 尽 可 能 地 把 它 们 本 地 化 和 封 装 成 专 门 的 函 数 。<br />

规 则 3.5( 强 制 ):<br />

如 果 做 为 其 他 特 性 的 支 撑 , 实 现 定 义 (implementation-defined) 的 行<br />

为 和 位 域 (bitfields) 集 合 应 当 文 档 化 。<br />

[ 未 指 定 10; 实 现 30、31]<br />

这 是 在 使 用 了 规 则 6.4 和 规 则 6.5 中 描 述 的 非 良 好 定 义 的 位 域 时 遇 到 的 特 定 问 题 。C 当 中<br />

的 位 域 是 该 语 言 中 最 缺 乏 良 好 定 义 的 部 分 之 一 。 位 域 的 使 用 可 能 体 现 在 两 个 主 要 方 面 :<br />

• 为 了 在 大 的 数 据 类 型 ( 同 union 一 起 ) 中 访 问 独 立 的 数 据 位 或 成 组 数 据 位 。 该 用 法 是<br />

不 允 许 的 ( 见 规 则 18.4)。<br />

• 为 了 访 问 用 于 节 省 存 储 空 间 而 打 包 的 标 志 (flags) 或 其 他 短 型 (short-length) 数 据 。<br />

为 了 有 效 利 用 存 储 空 间 而 做 的 短 型 数 据 的 打 包 , 是 本 文 档 所 设 想 的 唯 一 可 接 受 的 位 域 使<br />

用 。 假 定 结 构 元 素 只 能 以 其 名 字 来 访 问 , 那 么 程 序 员 就 无 需 设 想 结 构 体 中 位 域 的 存 储 方 式 。<br />

我 们 建 议 结 构 的 声 明 要 保 持 位 域 的 设 置 , 并 且 在 同 一 个 结 构 中 不 得 包 含 其 他 任 何 数 据 。<br />

要 注 意 的 是 , 在 定 义 位 域 的 时 候 不 需 要 追 随 规 则 6.3, 因 为 它 们 的 长 度 已 经 定 义 在 结 构 中 了 。<br />

如 果 编 译 器 带 有 一 个 开 关 以 强 制 位 域 遵 循 某 个 特 定 的 布 局 , 那 么 它 有 助 于 下 面 的 判 断 。<br />

例 如 下 面 可 接 受 的 代 码 :<br />

struct message /* Struct is for bit-fields only */<br />

{<br />

signed int little: 4; /* Note: use of basic types is required */<br />

unsigned int x_set: 1;<br />

unsigned int y_set: 1;<br />

}message_chunk;<br />

如 果 要 使 用 位 域 , 就 得 注 意 实 现 定 义 的 行 为 所 存 在 的 领 域 及 其 潜 藏 的 缺 陷 ( 意 即 不 可 移<br />

植 性 )。 特 别 地 , 程 序 员 应 当 注 意 如 下 问 题 :<br />

• 位 域 在 存 储 单 元 中 的 分 配 是 实 现 定 义 (implementation-defined) 的 , 也 就 是 说 , 它 们<br />

在 存 储 单 元 ( 通 常 是 一 个 字 节 ) 中 是 高 端 在 后 (high end) 还 是 低 端 在 后 (low end)<br />

的 。<br />

• 位 域 是 否 重 叠 了 存 储 单 元 的 界 限 同 样 是 实 现 定 义 的 行 为 ( 例 如 , 如 果 顺 序 存 储 一 个 6<br />

位 的 域 和 一 个 4 位 的 域 , 那 么 4 位 的 域 是 全 部 从 新 的 字 节 开 始 , 还 是 其 中 2 位 占 据<br />

一 个 字 节 中 的 剩 余 2 位 而 其 他 2 位 开 始 于 下 个 字 节 )。<br />

规 则 3.6( 强 制 ):<br />

产 品 代 码 中 使 用 的 所 有 库 都 要 适 应 本 文 档 给 出 的 要 求 , 并 且 要 经 过 适<br />

当 的 验 证 。<br />

20


[IEC 61508 Part 3]<br />

本 规 则 的 对 象 是 产 品 代 码 中 的 任 意 库 , 因 此 这 些 库 可 能 包 含 编 译 器 提 供 的 标 准 库 、 其 他<br />

第 三 方 的 库 或 者 实 验 室 中 自 己 开 发 的 库 。 这 是 由 IEC 61508 Part 3 建 议 的 。<br />

6.4 字 符 集<br />

规 则 4.1( 强 制 ): 只 能 使 用 ISO C 标 准 中 定 义 的 escape 序 列 。<br />

参 见 5.2.2 节 中 关 于 有 效 escape 序 列 的 ISO 标 准 。<br />

规 则 4.2( 强 制 ):<br />

不 能 使 用 三 字 母 词 (trigraphs)。<br />

[ 未 定 义 11; 实 现 11]<br />

三 字 母 词 由 2 个 问 号 序 列 后 跟 1 个 确 定 字 符 组 成 ( 如 ,??- 代 表 “~”( 非 ) 符 号 , 而 ??)<br />

代 表 “]” 符 号 )。 它 们 可 能 会 对 2 个 问 号 标 记 的 其 他 使 用 造 成 意 外 的 混 淆 , 例 如 字 符 串<br />

“(Date should be in the form ??-??-??)”<br />

将 不 会 表 现 为 预 期 的 那 样 , 实 际 上 它 被 编 译 器 解 释 为<br />

“(Date should be in the form ~~)”<br />

6.5 标 识 符<br />

规 则 5.1( 强 制 ): 标 识 符 ( 内 部 的 和 外 部 的 ) 的 有 效 字 符 不 能 多 于 31。<br />

[ 未 定 义 7; 实 现 5、6]<br />

ISO 标 准 要 求 在 内 部 标 识 符 之 间 前 31 个 字 符 必 须 是 不 同 的 以 保 证 可 移 植 性 。 即 使 编 译 器<br />

支 持 , 也 不 能 超 出 这 个 限 制 。<br />

ISO 标 准 要 求 外 部 标 识 符 之 间 前 6 个 字 符 必 须 是 不 同 的 ( 忽 略 大 小 写 ) 以 保 证 最 佳 的 可 移<br />

植 性 。 然 而 这 条 限 制 相 当 严 格 并 被 认 为 不 是 必 须 的 。 本 规 则 的 意 图 是 为 了 在 一 定 程 度 上 放 宽<br />

ISO 标 准 的 要 求 以 适 应 当 今 的 环 境 , 但 应 当 确 保 31 个 字 符 / 大 小 写 的 有 效 性 是 可 以 由 实 现 所 支<br />

持 的 。<br />

使 用 标 识 符 名 称 要 注 意 的 一 个 相 关 问 题 是 发 生 在 名 称 之 间 只 有 一 个 字 符 或 少 数 字 符 不 同<br />

的 情 况 , 特 别 是 名 称 比 较 长 时 , 当 名 称 间 的 区 别 很 容 易 被 误 读 时 问 题 就 比 较 显 著 , 比 如 1( 数<br />

字 1) 和 l(L 的 小 写 )、0 和 O、2 和 Z、5 和 S, 或 者 n 和 h。 建 议 名 称 间 的 区 别 要 显 而 易 见 。<br />

在 这 问 题 上 的 特 定 方 针 可 以 放 在 风 格 指 南 中 ( 见 4.2.2 节 )。<br />

规 则 5.2( 强 制 ):<br />

具 有 内 部 作 用 域 的 标 识 符 不 应 使 用 与 具 有 外 部 作 用 域 的 标 识 符 相 同 的<br />

名 称 , 这 会 隐 藏 了 外 部 标 识 符 。<br />

外 部 作 用 域 和 内 部 作 用 域 的 定 义 如 下 。 文 件 范 围 内 的 标 识 符 可 以 看 做 是 具 有 最 外 部<br />

(outermost) 的 作 用 域 ; 块 范 围 内 的 标 识 符 看 做 是 具 有 更 内 部 (more inner) 的 作 用 域 ; 连 续<br />

嵌 套 的 块 , 其 作 用 域 更 深 入 。 本 规 则 只 是 不 允 许 一 个 第 二 深 层 (second inner) 的 定 义 隐 藏 其<br />

外 层 的 定 义 , 如 果 第 二 个 定 义 没 有 隐 藏 第 一 个 定 义 , 那 么 就 不 算 违 反 本 规 则 。<br />

在 嵌 套 的 范 围 中 , 使 用 相 同 名 称 的 标 识 符 隐 藏 其 他 标 识 符 会 使 得 代 码 非 常 混 乱 。 例 如 :<br />

int16_t i;<br />

{<br />

int16_t i; /* This is a different variable */<br />

/* This is not compliant */<br />

i = 3; /* It could be confusing as to which I this refers */<br />

}<br />

21


规 则 5.3( 强 制 ): typedef 的 名 字 应 当 是 唯 一 的 标 识 符 。<br />

typedef 的 名 称 不 能 重 用 , 不 管 是 做 为 其 他 typedef 或 者 任 何 目 的 。 例 如 :<br />

{<br />

}<br />

{<br />

}<br />

{<br />

}<br />

typedef unsigned char uint8_t;<br />

typedef unsigned char uint8_t; /* Not compliant – redefinition */<br />

unsigned char uint8_t; /* Not compliant – reuse of uint8_t */<br />

typedef 的 名 称 不 能 在 程 序 中 的 任 何 地 方 重 用 。 如 果 类 型 定 义 是 在 头 文 件 中 完 成 的 , 而 该<br />

头 文 件 被 多 个 源 文 件 包 含 , 不 算 违 背 本 规 则 。<br />

规 则 5.4( 强 制 ): 标 签 (tag) 名 称 必 须 是 唯 一 的 标 识 符 。<br />

程 序 中 标 签 的 名 字 不 可 重 用 , 不 管 是 做 为 另 外 的 标 签 还 是 出 于 其 他 目 的 。ISO 9899:1990 [2]<br />

没 有 定 义 当 一 个 聚 合 体 的 声 明 以 不 同 形 式 的 类 型 标 识 符 (struct 或 union) 使 用 同 一 个 标 签 时<br />

的 行 为 。 标 签 的 所 有 使 用 或 者 用 于 结 构 类 型 标 识 符 , 或 者 用 于 联 合 类 型 标 识 符 , 例 如 :<br />

struct stag { uint16_t a; uint16_t b; };<br />

struct stag a1 = { 0, 0 }; /* Compliant – compatible with above */<br />

union stag a2 = { 0, 0 }; /* Not compliant – not compatible with<br />

previous declarations */<br />

void foo (void)<br />

{<br />

struct stag { uint16_t a; }; /* Not compliant – tag stag redefined */<br />

}<br />

如 果 类 型 定 义 是 在 头 文 件 中 完 成 的 , 且 头 文 件 被 多 个 源 文 件 包 含 , 那 么 规 则 不 算 违 背 。<br />

规 则 5.5( 建 议 ): 具 有 静 态 存 储 期 的 对 象 或 函 数 标 识 符 不 能 重 用 。<br />

不 管 作 用 域 如 何 , 具 有 静 态 存 储 期 的 标 识 符 都 不 应 在 系 统 内 的 所 有 源 文 件 中 重 用 。 它 包<br />

含 带 有 外 部 链 接 的 对 象 或 函 数 , 及 带 有 静 态 存 储 类 标 识 符 的 任 何 对 象 或 函 数 。<br />

由 于 编 译 器 能 够 理 解 这 一 点 而 且 决 不 会 发 生 混 淆 , 那 么 对 用 户 来 说 就 存 在 着 把 不 相 关 的<br />

变 量 以 相 同 名 字 联 系 起 来 的 可 能 性 。<br />

这 种 混 淆 的 例 子 之 一 是 , 在 一 个 文 件 中 存 在 一 个 具 有 内 部 链 接 的 标 识 符 , 而 在 另 外 一 个<br />

文 件 中 存 在 着 具 有 外 部 链 接 的 相 同 名 字 的 标 识 符 。<br />

规 则 5.6( 建 议 ):<br />

一 个 命 名 空 间 中 不 应 存 在 与 另 外 一 个 命 名 空 间 中 的 标 识 符 拼 写 相 同 的<br />

标 识 符 , 除 了 结 构 和 联 合 中 的 成 员 名 字 。<br />

命 名 空 间 与 作 用 域 (scope) 是 不 同 的 , 本 规 则 不 考 虑 作 用 域 。 例 如 ,ISO C 允 许 在 一 个<br />

作 用 域 内 为 标 签 (tag) 和 typedef 使 用 相 同 的 标 识 符 (vector)<br />

typedef struct vector ( uint16_t x ; uint16_t y ; uint16_t z ; ) vector ;<br />

/* Rule violation ^^ ^^ */<br />

ISO C 定 义 了 许 多 不 同 的 命 名 空 间 ( 见 ISO 9899 :1990 6.1.2.3 [2])。 技 术 上 , 在 彼 此 独 立<br />

的 命 名 空 间 中 使 用 相 同 的 名 字 以 代 表 完 全 不 同 的 项 目 是 可 能 的 , 然 而 由 于 会 引 起 混 淆 , 通 常<br />

22


不 赞 成 这 种 做 法 , 因 此 即 使 是 在 独 立 的 命 名 空 间 中 名 字 也 不 能 重 用 。<br />

下 面 给 出 了 违 背 此 规 则 的 例 子 , 其 中 value 在 不 经 意 中 代 替 了 record.value:<br />

struct { int16_t key ; int16_t value ; } record ;<br />

int16_t value; /* Rule violation – 2 nd use of value */<br />

record.key = 1;<br />

value = 0; /* should have been record.value */<br />

相 比 之 下 , 下 面 的 例 子 没 有 违 背 此 规 则 , 因 为 两 个 成 员 名 字 不 会 引 起 混 淆 :<br />

struct device_q { struct device_q *next ; /* ... */ }<br />

devices[N_DEVICES] ;<br />

struct task_q { struct task_q *next ; /* … */ }<br />

tasks[N_TASKS];<br />

device[0].next = &devices[1];<br />

tasks[0].next = &tasks[1];<br />

规 则 5.7( 建 议 ): 不 能 重 用 标 识 符 名 字 。<br />

不 考 虑 作 用 域 , 系 统 内 任 何 文 件 中 不 应 重 用 标 识 符 。 本 规 则 和 规 则 5.2、5.3、5.4、5.5 和<br />

5.6 一 同 使 用 。<br />

struct air_speed<br />

{<br />

uint16_t speed; /* knots */<br />

} *x;<br />

struct gnd_speed<br />

{<br />

uint16_t speed; /* mph */<br />

/* Not Compliant – speed is in different units */<br />

} *y;<br />

x->speed = y->speed;<br />

当 标 识 符 名 字 用 在 头 文 件 且 头 文 件 包 含 在 多 个 源 文 件 中 时 , 不 算 违 背 本 规 则 。 使 用 严 格<br />

的 命 名 规 范 可 以 支 持 本 规 则 。<br />

6.6 类 型<br />

规 则 6.1( 强 制 ): 单 纯 的 char 类 型 应 该 只 用 做 存 储 和 使 用 字 符 值 。<br />

[ 实 现 14]<br />

规 则 6.2( 强 制 ): signed char 和 unsigned char 类 型 应 该 只 用 做 存 储 和 使 用 数 字 值 。<br />

有 三 种 不 同 的 char 类 型 :( 单 纯 的 )char、unsigned char、signed char。unsigned char 和 signed<br />

char 用 于 数 字 型 数 据 ,char 用 于 字 符 型 数 据 。 单 纯 char 类 型 的 符 号 是 实 现 定 义 的 , 不 应 依 赖 。<br />

单 纯 char 类 型 所 能 接 受 的 操 作 只 有 赋 值 和 等 于 操 作 符 (=、==、!=)。<br />

规 则 6.3( 建 议 ): 应 该 使 用 指 示 了 大 小 和 符 号 的 typedef 以 代 替 基 本 数 据 类 型 。<br />

不 应 使 用 基 本 数 值 类 型 char、int、short、long、float 和 doulbe, 而 应 使 用 特 定 长 度<br />

(specific-length) 的 typedef。 规 则 6.3 帮 助 我 们 认 清 存 储 类 型 的 大 小 , 却 不 能 保 证 可 移 植 性 ,<br />

23


这 是 因 为 整 数 提 升 (integral promotion) 的 不 对 称 性 。 关 于 整 数 提 升 的 讨 论 , 见 节 6.10。 仍 然<br />

很 重 要 的 是 要 理 解 整 数 大 小 的 实 现 。<br />

程 序 员 应 该 注 意 这 些 定 义 之 下 的 typedef 的 实 际 实 现 。<br />

比 如 , 本 文 档 中 建 议 为 所 有 基 本 数 值 类 型 和 字 符 类 型 使 用 如 下 所 示 的 ISO(POSIX) 的<br />

typedef。 对 于 32 位 计 算 机 , 它 们 是 :<br />

typedef char char_t;<br />

typedef signed char int8_t;<br />

typedef signed short int16_t;<br />

typedef signed int int32_t;<br />

typedef signed long int64_t;<br />

typedef unsigned char uint8_t;<br />

typedef unsigned short uint16_t;<br />

typedef unsigned int uint32_t;<br />

typedef unsigned long uint64_t;<br />

typedef float float32_t;<br />

typedef double float64_t;<br />

typedef long double float128_t;<br />

在 位 域 类 型 的 说 明 中 ,typedef 是 不 必 要 的 。<br />

规 则 6.4( 强 制 ): 位 域 只 能 被 定 义 为 unsigned int 或 singed int 类 型 。<br />

[ 未 定 义 38; 实 现 29]<br />

因 为 int 类 型 的 位 域 可 以 是 signed 或 unsigned, 使 用 int 是 由 实 现 定 义 的 。 由 于 其 行 为 未<br />

被 定 义 , 所 以 不 允 许 为 位 域 使 用 enum、short 或 char 类 型 。<br />

规 则 6.5( 强 制 ): unsigned int 类 型 的 位 域 至 少 应 该 为 2 bits 长 度 。<br />

1 bit 长 度 的 有 符 号 位 域 是 无 用 的 。<br />

6.7 常 量<br />

规 则 7.1( 强 制 ): 不 应 使 用 八 进 制 常 量 ( 零 除 外 ) 和 八 进 制 escape 序 列 。<br />

[Koenig 9]<br />

任 何 以 “0”( 零 ) 开 始 的 整 型 常 量 都 被 看 做 是 八 进 制 的 , 所 以 这 是 危 险 的 , 如 在 书 写 固<br />

定 长 度 的 常 量 时 。 例 如 , 下 面 为 3 个 数 字 位 的 总 线 消 息 做 数 组 初 始 化 时 将 产 生 非 预 期 的 结 果<br />

(052 是 八 进 制 的 , 即 十 进 制 的 42):<br />

code[1] = 109; /* equivalent to decimal 109 */<br />

code[2] = 100; /* equivalent to decimal 100 */<br />

code[3] = 052; /* equivalent to decimal 42 */<br />

code[4] = 071; /* equivalent to decimal 57 */<br />

八 进 制 的 escape 序 列 是 有 问 题 的 , 这 是 因 为 在 八 进 制 escape 结 尾 不 经 意 引 入 一 个 十 进 制<br />

数 会 产 生 另 外 一 个 字 符 。 下 面 例 子 中 , 第 一 个 表 达 式 的 值 是 实 现 定 义 的 , 因 为 其 字 符 常 量 包<br />

含 了 两 个 字 符 ,“\10” 和 “9”。 第 二 个 字 符 常 量 表 达 式 包 含 了 单 一 字 符 “\100”, 如 果 字 符 64<br />

不 在 基 本 运 算 字 符 集 中 , 这 也 将 是 由 实 现 定 义 的 。<br />

code[5] = ‘\109’ ; /* implementation-defined, two character constant */<br />

24


code[6] = ‘\100’ ; /* set to 64, or implementation-defined */<br />

最 好 根 本 不 要 使 用 八 进 制 常 量 或 escape 序 列 , 并 且 要 静 态 检 查 它 们 是 否 出 现 。 整 数 常 量 0<br />

( 做 为 单 个 数 字 书 写 的 ) 严 格 说 来 是 八 进 制 常 量 , 然 而 在 此 规 则 下 它 也 是 允 许 的 。<br />

6.8 声 明 与 定 义<br />

规 则 8.1( 强 制 ):<br />

函 数 应 当 具 有 原 型 声 明 , 且 原 型 在 函 数 的 定 义 和 调 用 范 围 内 都 是 可 见<br />

的 。<br />

[ 未 定 义 22、23]<br />

原 型 的 使 用 使 得 编 译 器 能 够 检 查 函 数 定 义 和 调 用 的 完 整 性 。 如 果 没 有 原 型 , 就 不 会 迫 使<br />

编 译 器 检 查 出 函 数 调 用 当 中 的 一 定 错 误 ( 比 如 , 函 数 体 具 有 不 同 的 参 数 数 目 , 调 用 和 定 义 之<br />

间 参 数 类 型 的 不 匹 配 )。 事 实 证 明 , 函 数 接 口 是 相 当 多 问 题 的 肇 因 , 因 此 本 规 则 是 相 当 重 要 的 。<br />

对 外 部 函 数 来 说 , 我 们 建 议 采 用 如 下 方 法 , 在 头 文 件 中 声 明 函 数 ( 亦 即 给 出 其 原 型 ), 并<br />

在 所 有 需 要 该 函 数 原 型 的 代 码 文 件 中 包 含 这 个 头 文 件 ( 见 规 则 8.8)。<br />

为 具 有 内 部 链 接 的 函 数 给 出 其 原 型 也 是 良 好 的 编 程 实 践 。<br />

规 则 8.2( 强 制 ): 不 论 何 时 声 明 或 定 义 了 一 个 对 象 或 函 数 , 它 的 类 型 都 应 显 式 声 明 。<br />

extern x; /* Non-compliant – implicit int type */<br />

extern int16_t x ; /* Compliant – explicit type */<br />

const y ; /* Non-compliant – implicit int type */<br />

const int16_t y ; /* Compliant – explicit type */<br />

static foo (void) ; /* Non-compliant – implicit type */<br />

static int16_t foo (void) ; /* Compliant – explicit type */<br />

规 则 8.3( 强 制 ):<br />

函 数 的 每 个 参 数 类 型 在 声 明 和 定 义 中 必 须 是 等 同 的 , 函 数 的 返 回 类 型<br />

也 该 是 等 同 的 。<br />

[ 未 定 义 24;Koenig 59 – 62]<br />

参 数 与 返 回 值 的 类 型 在 原 型 和 定 义 中 必 须 匹 配 , 这 不 仅 要 求 等 同 的 基 本 类 型 , 也 要 求 包<br />

含 typedef 名 称 和 限 定 词 在 内 的 类 型 也 要 相 同 。<br />

规 则 8.4( 强 制 ): 如 果 对 象 或 函 数 被 声 明 了 多 次 , 那 么 它 们 的 类 型 应 该 是 兼 容 的 。<br />

[ 未 定 义 10]<br />

兼 容 类 型 的 定 义 是 冗 长 复 杂 的 ( 详 见 ISO 9899 :1990 [2], 节 6.1.2.6、6.5.2、6.5.3、6.5.4)。<br />

两 个 等 同 的 类 型 必 然 是 兼 容 的 , 而 两 个 兼 容 的 类 型 不 需 要 等 同 。 例 如 , 下 面 的 类 型 对 是 兼 容<br />

的 :<br />

signed int<br />

int<br />

char[5] char []<br />

unsigned short int unsigend short<br />

规 则 8.5( 强 制 ): 头 文 件 中 不 应 有 对 象 或 函 数 的 定 义 。<br />

头 文 件 应 该 用 于 声 明 对 象 、 函 数 、typedef 和 宏 , 而 不 应 该 包 含 或 生 成 占 据 存 储 空 间 的 对<br />

象 或 函 数 ( 或 它 们 的 片 断 ) 的 定 义 。 这 样 就 清 晰 地 划 分 了 只 有 C 文 件 才 包 含 可 执 行 的 源 代 码 ,<br />

而 头 文 件 只 能 包 含 声 明 。<br />

规 则 8.6( 强 制 ): 函 数 应 该 声 明 为 具 有 文 件 作 用 域 。<br />

[ 未 定 义 36]<br />

25


在 块 作 用 域 中 声 明 函 数 会 引 起 混 淆 并 可 能 导 致 未 定 义 的 行 为 。<br />

规 则 8.7( 强 制 ): 如 果 对 象 的 访 问 只 是 在 单 一 的 函 数 中 , 那 么 对 象 应 该 在 块 范 围 内 声 明 。<br />

可 能 的 情 况 下 , 对 象 的 作 用 域 应 该 限 制 在 函 数 内 。 只 有 当 对 象 需 要 具 有 内 部 或 外 部 链 接<br />

时 才 能 为 其 使 用 文 件 作 用 域 。 当 在 文 件 范 围 内 声 明 对 象 时 , 使 用 规 则 8.10。 良 好 的 编 程 实 践<br />

是 , 在 不 必 要 的 情 况 下 避 免 使 用 全 局 标 识 符 。 对 象 声 明 在 最 外 层 或 最 内 层 的 做 法 主 要 是 种 风<br />

格 问 题 。<br />

规 则 8.8( 强 制 ): 外 部 对 象 或 函 数 应 该 声 明 在 唯 一 的 文 件 中 。<br />

[Koenig 66]<br />

通 常 这 意 味 着 在 一 个 头 文 件 中 声 明 一 个 外 部 标 识 符 , 而 在 定 义 或 使 用 该 标 识 符 的 任 何 文<br />

件 中 包 含 这 个 头 文 件 。 例 如 , 在 头 文 件 featureX.h 中 声 明 :<br />

extern int16_t a ;<br />

然 后 对 a 进 行 定 义 :<br />

#include <br />

int16_t a = 0 ;<br />

工 程 中 存 在 的 头 文 件 可 能 是 一 个 或 多 个 , 但 是 任 何 一 个 外 部 对 象 或 函 数 都 只 能 在 一 个 头<br />

文 件 中 声 明 。<br />

规 则 8.9( 强 制 ): 具 有 外 部 链 接 的 标 识 符 应 该 具 有 准 确 的 外 部 定 义 。<br />

[ 未 定 义 44;Koenig 55、63 – 65]<br />

一 个 标 识 符 如 果 存 在 多 个 定 义 ( 在 不 同 的 文 件 中 ) 或 者 甚 至 没 有 定 义 , 那 么 其 行 为 是 未<br />

经 定 义 的 。 不 同 文 件 中 的 多 个 定 义 是 不 允 许 的 , 即 使 这 些 定 义 相 同 也 不 允 许 ; 进 而 如 果 这 些<br />

定 义 不 同 或 者 标 识 符 的 初 始 值 不 同 , 问 题 显 然 很 严 重 。<br />

规 则 8.10( 强 制 ):<br />

在 文 件 范 围 内 声 明 和 定 义 的 所 有 对 象 或 函 数 应 该 具 有 内 部 链 接 , 除 非<br />

是 在 需 要 外 部 链 接 的 情 况 下 。<br />

[Koenig 56、57]<br />

如 果 一 个 变 量 只 是 被 同 一 文 件 中 的 函 数 所 使 用 , 那 么 就 用 static。 类 似 地 , 如 果 一 个 函 数<br />

只 是 在 同 一 文 件 中 的 其 他 地 方 调 用 , 那 么 就 用 static。 使 用 static 存 储 类 标 识 符 将 确 保 标 识 符 只<br />

是 在 声 明 它 的 文 件 中 是 可 见 的 , 并 且 避 免 了 和 其 他 文 件 或 库 中 的 相 同 标 识 符 发 生 混 淆 的 可 能<br />

性 。<br />

规 则 8.11( 强 制 ):<br />

明 。<br />

static 存 储 类 标 识 符 应 该 用 于 具 有 内 部 链 接 的 对 象 和 函 数 的 定 义 和 声<br />

static 和 extern 存 储 类 标 识 符 常 常 是 产 生 混 淆 的 原 因 。 良 好 的 编 程 习 惯 是 , 把 static 关 键 字<br />

一 致 地 应 用 在 所 有 具 有 内 部 链 接 的 对 象 和 函 数 的 声 明 上 。<br />

规 则 8.12( 强 制 ):<br />

当 一 个 数 组 声 明 为 具 有 外 部 链 接 , 它 的 大 小 应 该 显 式 声 明 或 者 通 过 初<br />

始 化 进 行 隐 式 定 义 。<br />

int array1[10] ; /* Compliant */<br />

extern int array2[] ; /* Not compliant */<br />

int array2[] = { 0, 10, 15 }; /* Compliant */<br />

[ 未 定 义 46]<br />

尽 管 可 以 在 数 组 声 明 不 完 善 时 访 问 其 元 素 , 然 而 仍 然 是 在 数 组 的 大 小 可 以 显 式 确 定 的 情<br />

况 下 , 这 样 做 才 会 更 为 安 全 。<br />

26


6.9 初 始 化<br />

规 则 9.1( 强 制 ): 所 有 自 动 变 量 在 使 用 前 都 应 被 赋 值 。<br />

本 规 则 的 意 图 是 使 所 有 变 量 在 其 被 读 之 前 已 经 写 过 了 , 除 了 声 明 中 的 初 始 化 。<br />

[ 未 定 义 41]<br />

注 意 , 根 据 ISO C 标 准 , 具 有 静 态 存 储 期 的 变 量 缺 省 地 被 自 动 赋 予 零 值 , 除 非 经 过 了 显<br />

式 的 初 始 化 。 实 际 中 , 一 些 嵌 入 式 环 境 没 有 实 现 这 样 的 缺 省 行 为 。 静 态 存 储 期 是 所 有 以 static<br />

存 储 类 形 式 声 明 的 变 量 或 具 有 外 部 链 接 的 变 量 的 共 同 属 性 , 自 动 存 储 期 变 量 通 常 不 是 自 动 初<br />

始 化 的 。<br />

规 则 9.2( 强 制 ): 应 该 使 用 大 括 号 以 指 示 和 匹 配 数 组 和 结 构 的 非 零 初 始 化 构 造 。<br />

[ 未 定 义 42]<br />

ISO C 要 求 数 组 、 结 构 和 联 合 的 初 始 化 列 表 要 以 一 对 大 括 号 括 起 来 ( 尽 管 不 这 样 做 的 行 为<br />

是 未 定 义 的 )。 本 规 则 更 进 一 步 地 要 求 , 使 用 附 加 的 大 括 号 来 指 示 嵌 套 的 结 构 。 它 迫 使 程 序 员<br />

显 式 地 考 虑 和 描 述 复 杂 数 据 类 型 元 素 ( 比 如 , 多 维 数 组 ) 的 初 始 化 次 序 。<br />

例 如 , 下 面 的 例 子 是 二 维 数 组 初 始 化 的 有 效 ( 在 ISO C 中 ) 形 式 , 但 第 一 个 与 本 规 则 相<br />

违 背 :<br />

int16_t y[3][2] = { 1, 2, 3, 4, 5, 6 }; /* not compliant */<br />

int16_t y[3][2] = { { 1, 2 }, { 3, 4 }, { 5, 6 } } ; /* compliant */<br />

在 结 构 中 以 及 在 结 构 、 数 组 和 其 他 类 型 的 嵌 套 组 合 中 , 规 则 类 似 。<br />

还 要 注 意 的 是 , 数 组 或 结 构 的 元 素 可 以 通 过 只 初 始 化 其 首 元 素 的 方 式 初 始 化 ( 为 0 或<br />

NULL)。 如 果 选 择 了 这 样 的 初 始 化 方 法 , 那 么 首 元 素 应 该 被 初 始 化 为 0( 或 NULL), 此 时 不<br />

需 要 使 用 嵌 套 的 大 括 号 。<br />

ISO 标 准 [2] 包 含 了 更 多 的 初 始 化 例 子 。<br />

规 则 9.3( 强 制 ):<br />

在 枚 举 列 表 中 ,“=” 不 能 显 式 用 于 除 首 元 素 之 外 的 元 素 上 , 除 非 所 有<br />

的 元 素 都 是 显 式 初 始 化 的 。<br />

如 果 枚 举 列 表 的 成 员 没 有 显 式 地 初 始 化 , 那 么 C 将 为 其 分 配 一 个 从 0 开 始 的 整 数 序 列 ,<br />

首 元 素 为 0, 后 续 元 素 依 次 加 1。<br />

如 上 规 则 允 许 的 , 首 元 素 的 显 式 初 始 化 迫 使 整 数 的 分 配 从 这 个 给 定 的 值 开 始 。 当 采 用 这<br />

种 方 法 时 , 重 要 的 是 确 保 所 用 初 始 化 值 一 定 要 足 够 小 , 这 样 列 表 中 的 后 续 值 就 不 会 超 出 该 枚<br />

举 常 量 所 用 的 int 存 储 量 。<br />

列 表 中 所 有 项 目 的 显 式 初 始 化 也 是 允 许 的 , 它 防 止 了 易 产 生 错 误 的 自 动 与 手 动 分 配 的 混<br />

合 。 然 而 , 程 序 员 就 该 担 负 职 责 以 保 证 所 有 值 都 处 在 要 求 的 范 围 内 以 及 值 不 是 被 无 意 复 制 的 。<br />

enum colour { red = 3, blue, green, yellow = 5 } ; /* not compliant */<br />

/* green and yellow represent the same value – this is duplication */<br />

enum colour { red = 3, blue = 4, green = 5, yellow = 5 }; /* compliant */<br />

/* green and yellow represent the same value – this is duplication */<br />

6.10 数 值 类 型 转 换<br />

6.10.1 隐 式 和 显 式 类 型 转 换<br />

C 语 言 给 程 序 员 提 供 了 相 当 大 的 自 由 度 并 允 许 不 同 数 值 类 型 可 以 自 动 转 换 。 由 于 某 些 功 能<br />

性 的 原 因 可 以 引 入 显 式 的 强 制 转 换 , 例 如 :<br />

27


• 用 以 改 变 类 型 使 得 后 续 的 数 值 操 作 可 以 进 行<br />

• 用 以 截 取 数 值<br />

• 出 于 清 晰 的 角 度 , 用 以 执 行 显 式 的 类 型 转 换<br />

为 了 代 码 清 晰 的 目 的 而 插 入 的 强 制 转 换 通 常 是 有 用 的 , 但 如 果 过 多 使 用 就 会 导 致 程 序 的<br />

可 读 性 下 降 。 正 如 下 面 所 描 述 的 , 一 些 隐 式 转 换 是 可 以 安 全 地 忽 略 的 , 而 另 一 些 则 不 能 。<br />

6.10.2 隐 式 转 换 的 类 型<br />

存 在 三 种 隐 式 转 换 的 类 别 需 要 加 以 区 分 。<br />

整 数 提 升 (Integral promotion) 转 换<br />

整 数 提 升 描 述 了 一 个 过 程 , 借 此 过 程 数 值 操 作 总 是 在 int 或 long(signed 或 unsigned) 整<br />

型 操 作 数 上 进 行 。 其 他 整 型 操 作 数 (char、short、bit-field 和 enum) 在 数 值 操 作 前 总 是 先 转 化<br />

为 int 或 unsigned int 类 型 。 这 些 类 型 称 为 small integer 类 型 。<br />

整 数 提 升 的 规 则 命 令 , 在 大 多 数 数 值 操 作 中 , 如 果 int 类 型 能 够 代 表 原 来 类 型 的 所 有 值 ,<br />

那 么 small integer 类 型 的 操 作 数 要 被 转 化 为 int 类 型 ; 否 则 就 被 转 化 为 unsigned int。<br />

注 意 , 整 数 提 升 :<br />

• 仅 仅 应 用 在 small integer 类 型 上<br />

• 应 用 在 一 元 、 二 元 和 三 元 操 作 数 上<br />

• 不 能 用 在 逻 辑 操 作 符 (&&、||、!) 的 操 作 数 上<br />

• 用 在 switch 语 句 的 控 制 表 达 式 上<br />

整 数 提 升 经 常 和 操 作 数 的 “ 平 衡 ”(balancing, 后 面 提 到 ) 发 生 混 淆 。 事 实 上 , 整 数 提 升<br />

发 生 在 一 元 操 作 的 过 程 中 , 如 果 二 元 操 作 的 两 个 操 作 数 是 同 样 类 型 的 , 那 么 也 可 以 发 生 在 二<br />

元 操 作 之 上 。<br />

由 于 整 数 提 升 , 两 个 类 型 为 unsigned short 的 对 象 相 加 的 结 果 总 是 signed int 或 unsigned int<br />

类 型 的 ; 事 实 上 , 加 法 是 在 后 面 两 种 类 型 上 执 行 的 。 因 此 对 于 这 样 的 操 作 , 就 有 可 能 获 得 一<br />

个 其 值 超 出 了 原 始 操 作 数 类 型 大 小 的 结 果 。 例 如 , 如 果 int 类 型 的 大 小 是 32 位 , 那 么 就 能 够<br />

把 两 个 short(16 位 ) 类 型 的 对 象 相 乘 并 获 得 一 个 32 位 的 结 果 , 而 没 有 溢 出 的 危 险 。 另 一 方<br />

面 , 如 果 int 类 型 仅 是 16 位 , 那 么 两 个 16 位 对 象 的 乘 积 将 只 能 产 生 一 个 16 位 的 结 果 , 同 时<br />

必 须 对 操 作 数 的 大 小 给 出 适 当 的 限 制 。<br />

整 数 提 升 还 可 以 应 用 在 一 元 操 作 符 上 。 例 如 , 对 一 个 unsigned char 操 作 数 执 行 位 非 (~)<br />

运 算 , 其 结 果 典 型 地 是 signed int 类 型 的 负 值 。<br />

整 数 提 升 是 C 语 言 中 本 质 上 的 不 一 致 性 , 在 这 当 中 small integer 类 型 的 行 为 与 long 和 int<br />

类 型 不 同 。<strong>MISRA</strong>-C 鼓 励 使 用 typedef。 然 而 , 由 于 众 多 整 型 的 行 为 是 不 一 致 的 , 忽 略 基 本 类<br />

型 ( 见 后 面 的 描 述 ) 可 能 是 不 安 全 的 , 除 非 对 表 达 式 的 构 造 方 式 给 出 一 些 限 制 。 后 面 规 则 的<br />

意 图 是 想 中 和 整 数 提 升 的 后 果 以 避 免 这 些 异 常 。<br />

赋 值 转 换<br />

赋 值 转 换 发 生 在 :<br />

• 赋 值 表 达 式 的 类 型 被 转 化 成 赋 值 对 象 的 类 型 时<br />

• 初 始 化 表 达 式 的 类 型 被 转 化 成 初 始 化 对 象 的 类 型 时<br />

• 函 数 调 用 参 数 的 类 型 被 转 化 成 函 数 原 型 中 声 明 的 形 式 参 数 的 类 型 时<br />

• 返 回 语 句 中 用 到 的 表 达 式 的 类 型 被 转 化 成 函 数 原 型 中 声 明 的 函 数 类 型 时<br />

• switch-case 标 签 中 的 常 量 表 达 式 的 类 型 被 转 化 成 控 制 表 达 式 的 提 升 类 型 时 。 这 个 转 换<br />

仅 用 于 比 较 的 目 的<br />

28


每 种 情 况 中 , 必 要 时 数 值 表 达 式 的 值 是 无 条 件 转 换 到 其 他 类 型 的 。<br />

平 衡 转 换 (Balancing conversions)<br />

平 衡 转 换 的 描 述 是 在 ISO C 标 准 中 的 “Usual Arithmetic Conversions” 条 目 下 。 这 套 规 则<br />

提 供 一 个 机 制 , 当 二 元 操 作 符 的 两 个 操 作 数 要 平 衡 为 一 个 通 用 类 型 时 或 三 元 操 作 符 (? :) 的 第<br />

二 、 第 三 个 操 作 数 要 平 衡 为 一 个 通 用 类 型 时 , 产 生 一 个 通 用 类 型 。 平 衡 转 换 总 是 涉 及 到 两 个<br />

不 同 类 型 的 操 作 数 ; 其 中 一 个 、 有 时 是 两 个 需 要 进 行 隐 式 转 换 。 整 数 提 升 ( 上 面 描 述 的 ) 的<br />

过 程 使 得 平 衡 转 换 规 则 变 得 复 杂 起 来 , 在 整 数 提 升 时 ,small integer 类 型 的 操 作 数 首 先 要 提 升<br />

到 int 或 unsigned int 类 型 。 整 数 提 升 是 常 见 的 数 值 转 换 , 即 使 两 个 操 作 数 的 类 型 一 致 。<br />

与 平 衡 转 换 明 显 相 关 的 操 作 符 是 :<br />

• 乘 除 *、/、%<br />

• 加 减 +、-<br />

• 位 操 作 &、^、|<br />

• 条 件 操 作 符 (… ? … : …)<br />

• 关 系 操 作 符 >、>=、


小 是 32 位 , 那 么 加 法 就 会 在 有 符 号 的 32 位 数 值 上 运 算 并 且 保 存 下 正 确 的 值 。 如 果 int 实<br />

现 的 大 小 仅 是 16 位 , 那 么 加 法 会 在 无 符 号 的 16 位 数 值 上 进 行 , 于 是 会 发 生 折 叠<br />

(wraparound) 现 象 并 产 生 值 4464(70000%65536)。 无 符 号 数 值 的 折 叠 (wraparound)<br />

是 经 过 良 好 定 义 的 甚 至 是 有 意 的 ; 但 也 会 存 在 潜 藏 的 混 淆 。<br />

• 类 型 计 算 的 混 淆 : 程 序 员 中 常 见 的 概 念 混 乱 也 会 产 生 类 似 的 问 题 , 人 们 经 常 会 以 为 参 与<br />

运 算 的 类 型 在 某 种 方 式 上 受 到 被 赋 值 或 转 换 的 结 果 类 型 的 影 响 。 例 如 , 在 下 面 的 代 码 中 ,<br />

两 个 16 位 对 象 进 行 16 位 的 加 法 运 算 ( 除 非 被 提 升 为 32 位 int), 其 结 果 在 赋 值 时 被 转 换<br />

为 uint32_t 类 型 。<br />

u32x = u16a + u16b;<br />

并 非 少 见 的 是 , 程 序 员 会 认 为 此 表 达 式 执 行 的 是 32 位 加 法 —— 因 为 u32x 的 类 型 。<br />

对 这 种 特 性 的 混 淆 不 只 局 限 于 整 数 运 算 或 隐 式 转 换 , 下 面 的 例 子 描 述 了 在 某 些 语 句 中 ,<br />

结 果 是 良 好 定 义 的 但 运 算 并 不 会 按 照 程 序 员 设 想 的 那 样 进 行 。<br />

u32a = (uint32_t) (u16a * u16b);<br />

f64a = u16a / u16b ;<br />

f32a = (float32_t) (u16a / u16b) ;<br />

f64a = f32a + f32b ;<br />

f64a = (float64_t) (f32a + f32b) ;<br />

• 数 学 运 算 中 符 号 的 改 变 : 整 数 提 升 经 常 会 导 致 两 个 无 符 号 的 操 作 数 产 生 一 个 (signed)int<br />

类 型 的 结 果 。 比 如 , 如 果 int 是 32 位 的 , 那 么 两 个 16 位 无 符 号 数 的 加 法 将 产 生 一 个 有 符<br />

号 的 32 位 结 果 ; 而 如 果 int 是 16 位 的 , 那 么 同 样 运 算 会 产 生 一 个 无 符 号 的 16 位 结 果 。<br />

• 位 运 算 中 符 号 的 改 变 : 当 位 运 算 符 应 用 在 无 符 号 短 整 型 时 , 整 数 提 升 会 有 某 些 特 别 不 利<br />

的 反 响 。 比 如 , 在 一 个 unsigned char 类 型 的 操 作 数 上 做 位 补 运 算 通 常 会 产 生 其 值 为 负 的<br />

(signed)int 类 型 结 果 。 在 运 算 之 前 , 操 作 数 被 提 升 为 int 类 型 , 并 且 多 出 来 的 那 些 高 位<br />

被 补 运 算 置 1。 那 些 多 余 位 的 个 数 , 若 有 的 话 , 依 赖 于 int 的 大 小 , 而 且 在 补 运 算 后 接 右<br />

移 运 算 是 危 险 的 。<br />

为 了 避 免 上 述 问 题 产 生 的 危 险 , 重 要 的 是 要 建 立 一 些 准 则 以 限 制 构 建 表 达 式 的 方 式 。 这<br />

里 首 先 给 出 某 些 概 念 的 定 义 。<br />

6.10.4 基 本 类 型 (underlying type)<br />

表 达 式 的 类 型 是 指 其 运 算 结 果 的 类 型 。 当 两 个 long 类 型 的 值 相 加 时 , 表 达 式 具 有 long 类<br />

型 。 大 多 数 数 值 运 算 符 产 生 其 类 型 依 赖 于 操 作 数 类 型 的 结 果 。 另 一 方 面 , 某 些 操 作 符 会 给 出<br />

具 有 int 类 型 的 布 尔 结 果 而 不 管 其 操 作 数 类 型 如 何 。 所 以 , 举 例 来 说 , 当 两 个 long 类 型 的 项 用<br />

关 系 运 算 符 做 比 较 时 , 该 表 达 式 的 类 型 为 int。<br />

术 语 “ 基 本 类 型 ” 的 定 义 是 , 在 不 考 虑 整 数 提 升 的 作 用 下 描 述 由 计 算 表 达 式 而 得 到 的 类<br />

型 。<br />

当 两 个 int 类 型 的 操 作 数 相 加 时 , 结 果 是 int 类 型 , 那 么 表 达 式 可 以 说 具 有 int 类 型 。<br />

当 两 个 unsigned char 类 型 的 数 相 加 时 , 结 果 也 是 int 类 型 ( 通 常 如 此 , 因 为 整 数 提 升 的 原<br />

因 ), 但 是 该 表 达 式 基 本 的 类 型 按 照 定 义 则 是 unsigned char。<br />

术 语 “ 基 本 类 型 ” 不 是 C 语 言 标 准 或 其 他 C 语 言 的 文 本 所 认 知 的 , 但 在 描 述 如 下 规 则 时<br />

它 很 有 用 。 它 描 述 了 一 个 假 想 的 对 C 语 言 的 违 背 , 其 中 不 存 在 整 数 提 升 而 且 常 用 的 数 值 转 换<br />

一 致 性 地 应 用 于 所 有 的 整 数 类 型 。 引 进 这 样 的 概 念 是 因 为 整 数 提 升 很 敏 感 且 有 时 是 危 险 的 。<br />

整 数 提 升 是 C 语 言 中 不 可 避 免 的 特 性 , 但 是 这 些 规 则 的 意 图 是 要 使 整 数 提 升 的 作 用 能 够 通 过<br />

不 利 用 发 生 在 small integer 操 作 数 上 的 宽 度 扩 展 来 中 和 。<br />

当 然 ,C 标 准 没 有 显 式 地 定 义 在 缺 乏 整 数 提 升 时 small integer 类 型 如 何 平 衡 为 通 用 类 型 ,<br />

尽 管 标 准 确 实 建 立 了 值 保 留 (value-perserving) 原 则 。<br />

30


当 int 类 型 的 数 相 加 时 , 程 序 员 必 须 要 确 保 运 算 结 果 不 会 超 出 int 类 型 所 能 体 现 的 值 。 如<br />

果 他 没 有 这 样 做 , 就 可 能 会 发 生 溢 出 而 结 果 值 是 未 定 义 的 。 这 里 描 述 的 方 法 意 欲 使 得 在 做 small<br />

integer 类 型 的 加 法 时 使 用 同 样 的 原 则 ; 程 序 员 要 确 保 两 个 unsigned char 类 型 的 数 相 加 的 结 果<br />

是 能 够 被 unsigned char 体 现 的 , 即 使 整 数 提 升 会 引 起 更 大 类 型 的 计 算 。 换 句 话 说 , 对 表 达 式<br />

基 本 类 型 的 遵 守 要 多 于 其 真 实 类 型 。<br />

整 数 常 量 表 达 式 的 基 本 类 型<br />

C 语 言 的 一 个 不 利 方 面 是 , 它 不 能 定 义 一 个 char 或 short 类 型 的 整 型 常 量 。 比 如 , 值 “5”<br />

可 以 通 过 附 加 的 一 个 合 适 的 后 缀 来 表 示 为 int、unsigned int、long 或 unsigned long 类 型 的 常 量 ;<br />

但 没 有 合 适 的 后 缀 用 来 创 建 不 同 的 char 或 short 类 型 的 常 量 形 式 。 这 为 维 护 表 达 式 中 的 类 型 一<br />

致 性 提 出 了 困 难 。 如 果 需 要 为 一 个 unsigned char 类 型 的 对 象 赋 值 , 那 么 或 者 要 承 受 对 一 个 整<br />

数 类 型 的 隐 式 转 换 , 或 者 要 实 行 强 制 转 换 。 很 多 人 会 辩 称 在 这 种 情 况 下 使 用 强 制 转 换 只 能 导<br />

致 可 读 性 下 降 。<br />

在 初 始 化 、 函 数 参 数 或 数 值 表 达 式 中 需 要 常 量 时 也 会 遇 到 同 样 的 问 题 。 然 而 只 要 遵 守 强<br />

类 型 (strong typing) 原 则 , 这 个 问 题 就 会 比 较 乐 观 。<br />

解 决 该 问 题 的 一 个 方 法 是 , 想 象 整 型 常 量 、 枚 举 常 量 、 字 符 常 量 或 者 整 型 常 量 表 达 式 具<br />

有 适 合 其 量 级 的 类 型 。 这 个 目 标 可 以 通 过 以 下 方 法 达 到 , 即 延 伸 基 本 类 型 的 概 念 到 整 型 常 量<br />

上 , 并 想 象 在 可 能 的 情 况 下 数 值 常 量 已 经 通 过 提 升 想 象 中 的 具 有 较 小 基 本 类 型 的 常 量 而 获 得 。<br />

这 样 , 整 型 常 量 表 达 式 的 基 本 类 型 就 可 以 如 下 定 义 :<br />

1. 如 果 表 达 式 的 真 实 类 型 是 (signed)int, 其 基 本 类 型 就 是 能 够 体 现 其 值 的 最 小 的 有 符 号 整<br />

型 。<br />

2. 如 果 表 达 式 的 真 实 类 型 是 unsigned int, 其 基 本 类 型 就 是 能 够 体 现 其 值 的 最 小 的 无 符 号 整<br />

型 。<br />

3. 在 所 有 其 他 情 况 下 , 表 达 式 的 基 本 类 型 与 其 真 实 类 型 相 同 。<br />

在 常 规 的 体 系 结 构 中 , 整 型 常 量 表 达 式 的 基 本 类 型 可 以 根 据 其 量 级 和 符 号 确 定 如 下 :<br />

无 符 号 值<br />

0U to 255U 8 bit unsigned<br />

256U to 65535U 16 bit unsigned<br />

65536U to 4294967295U 32 bit unsigned<br />

有 符 号 值<br />

-2147483648 to -32769 32 bit signed<br />

-32768 to -129 16 bit signed<br />

-128 to 127 8 bit signed<br />

128 to 32767 16 bit signed<br />

32768 to 2147483647 32 bit signed<br />

注 意 , 基 本 类 型 是 人 造 的 概 念 , 它 不 会 以 任 何 方 式 影 响 实 际 运 算 的 类 型 。 这 个 概 念 的 提<br />

出 只 是 为 了 定 义 一 个 在 其 中 可 以 构 建 数 值 表 达 式 的 安 全 框 架 。<br />

6.10.5 复 杂 表 达 式 (complex expressions)<br />

后 面 章 节 中 描 述 的 类 型 转 换 规 则 在 某 些 地 方 是 针 对 “ 复 杂 表 达 式 ” 的 概 念 。 术 语 “ 复 杂<br />

表 达 式 ” 意 味 着 任 何 不 是 如 下 类 型 的 表 达 式 :<br />

• 非 常 量 表 达 式<br />

• lvalue( 即 一 个 对 象 )<br />

• 函 数 的 返 回 值<br />

应 用 在 复 杂 表 达 式 的 转 换 也 要 加 以 限 制 以 避 免 上 面 总 结 出 的 危 险 。 特 别 地 , 表 达 式 中 的<br />

数 值 运 算 序 列 需 要 以 相 同 类 型 进 行 。<br />

31


以 下 是 复 杂 表 达 式 :<br />

s8a + s8b<br />

~u16a<br />

u16a >> 2<br />

foo (2) + u8a<br />

*ppc + 1<br />

++u8a<br />

以 下 不 是 复 杂 表 达 式 , 尽 管 某 些 包 含 了 复 杂 的 子 表 达 式 :<br />

pc[u8a]<br />

foo (u8a + u8b)<br />

++ppuc<br />

** (ppc + 1)<br />

pcbuf[s16a * 2]<br />

6.10.6 隐 式 类 型 转 换<br />

规 则 10.1( 强 制 ): 下 列 条 件 成 立 时 , 整 型 表 达 式 的 值 不 应 隐 式 转 换 为 不 同 的 基 本 类 型 :<br />

a) 转 换 不 是 带 符 号 的 向 更 宽 整 数 类 型 的 转 换 , 或 者<br />

b) 表 达 式 是 复 杂 表 达 式 , 或 者<br />

c) 表 达 式 不 是 常 量 而 是 函 数 参 数 , 或 者<br />

d) 表 达 式 不 是 常 量 而 是 返 回 的 表 达 式 。<br />

规 则 10.2( 强 制 ): 下 列 条 件 成 立 时 , 浮 点 类 型 表 达 式 的 值 不 应 隐 式 转 换 为 不 同 的 类 型 :<br />

a) 转 换 不 是 向 更 宽 浮 点 类 型 的 转 换 , 或 者<br />

b) 表 达 式 是 复 杂 表 达 式 , 或 者<br />

c) 表 达 式 是 函 数 参 数 , 或 者<br />

d) 表 达 式 是 返 回 表 达 式 。<br />

还 要 注 意 , 在 描 述 整 型 转 换 时 , 始 终 关 注 的 是 基 本 类 型 而 非 真 实 类 型 。<br />

这 两 个 规 则 广 泛 地 封 装 了 下 列 原 则 :<br />

• 有 符 号 和 无 符 号 之 间 没 有 隐 式 转 换<br />

• 整 型 和 浮 点 类 型 之 间 没 有 隐 式 转 换<br />

• 没 有 从 宽 类 型 向 窄 类 型 的 隐 式 转 换<br />

• 函 数 参 数 没 有 隐 式 转 换<br />

• 函 数 的 返 回 表 达 式 没 有 隐 式 转 换<br />

• 复 杂 表 达 式 没 有 隐 式 转 换<br />

限 制 复 杂 表 达 式 的 隐 式 转 换 的 目 的 , 是 为 了 要 求 在 一 个 表 达 式 里 的 数 值 运 算 序 列 中 , 所<br />

有 的 运 算 应 该 准 确 地 以 相 同 的 数 值 类 型 进 行 。 注 意 这 并 不 是 说 表 达 式 中 的 所 有 操 作 数 必 须 具<br />

备 相 同 的 类 型 。<br />

表 达 式 u32a + u16b + u16c 是 合 适 的 —— 两 个 加 法 在 概 念 上 (notionally) 都 以 U32 类 型<br />

进 行<br />

表 达 式 u16a + u16b + u32c 是 不 合 适 的 —— 第 一 个 加 法 在 概 念 上 以 U16 类 型 进 行 , 第 二 个<br />

32


加 法 是 U32 类 型 的 。<br />

使 用 名 词 “ 在 概 念 上 ” 是 因 为 , 在 实 际 中 数 值 运 算 的 类 型 将 依 赖 于 int 实 现 的 大 小 。 通 过<br />

遵 循 这 样 的 原 则 , 所 有 运 算 都 以 一 致 的 ( 基 本 ) 类 型 来 进 行 , 能 够 避 免 程 序 员 产 生 的 混 淆 和<br />

与 整 数 提 升 有 关 的 某 些 危 险 。<br />

extern void foo1 (uint8_t x);<br />

int16_t t1 (void)<br />

{<br />

…<br />

foo1 (u8a); /* compliant */<br />

foo1 (u8a + u8b); /* compliant */<br />

foo1 (s8a); /* not compliant */<br />

foo1 (u16a); /* not compliant */<br />

foo1 (2); /* not compliant */<br />

foo1 (2U); /* compliant */<br />

foo1 ( (uint8_t) 2 ); /* compliant */<br />

… s8a + u8a /* not compliant */<br />

… s8a + (int8_t) u8a /* compliant */<br />

s8b = u8a; /* not compliant */<br />

… u8a + 5 /* not compliant */<br />

… u8a + 5U /* compliant */<br />

… u8a + (uint8_t) 5 /* compliant */<br />

u8a = u16a; /* not compliant */<br />

u8a = (uint8_t) u16a; /* compliant */<br />

u8a = 5UL; /* not compliant */<br />

… u8a + 10UL /* compliant */<br />

u8a = 5U; /* compliant */<br />

… u8a + 3 /* not compliant */<br />

… u8a >> 3 /* compliant */<br />

… u8a >> 3U /* compliant */<br />

pca = “P”; /* compliant */<br />

… s32a + 80000 /* compliant */<br />

… s32a + 80000L /* compliant */<br />

f32a = f64a; /* not compliant */<br />

f32a = 2.5; /* not compliant –<br />

unsuffixed floating<br />

constants are of type<br />

double */<br />

u8a = u8b + u8c; /* compliant */<br />

s16a = u8b + u8b; /* not compliant */<br />

s32a = u8b + u8c; /* not compliant */<br />

33


f32a = 2.5F; /* compliant */<br />

u8a = f32a; /* not compliant */<br />

s32a = 1.0; /* not compliant */<br />

f32a = 1; /* not compliant */<br />

f32a = s16a; /* not compliant */<br />

… f32a + 1 /* not compliant */<br />

… f64a * s32a /* not compliant */<br />

…<br />

return (s32a); /* not compliant */<br />

…<br />

return (s16a); /* compliant */<br />

…<br />

return (20000); /* compliant */<br />

…<br />

return (20000L); /* not compliant */<br />

…<br />

return (s8a); /* not compliant */<br />

…<br />

return (u16a); /* not compliant */<br />

}<br />

int16_t foo2 (void)<br />

{<br />

…<br />

… (u16a + u16b) + u32a /* not compliant */<br />

… s32a + s8a + s8b /* compliant */<br />

… s8a + s8b + s32a /* not compliant */<br />

f64a = f32a + f32b; /* not compliant */<br />

f64a = f64b + f32a; /* compliant */<br />

f64a = s32a / s32b; /* not compliant */<br />

u32a = u16a + u16a; /* not compliant */<br />

s16a = s8a; /* compliant */<br />

s16a = s16b + 20000; /* compliant */<br />

s32a = s16a + 20000; /* not compliant */<br />

s32a = s16a + (int32_t) 20000; /* compliant */<br />

u16a = u16b + u8a; /* compliant */<br />

foo1 (u16a); /* not compliant */<br />

foo1 (u8a + u8b); /* compliant */<br />

…<br />

return s16a; /* compliant */<br />

…<br />

34


}<br />

return s8a; /* not compliant */<br />

6.10.7 显 式 转 换 ( 强 制 转 换 )<br />

规 则 10.3( 强 制 ):<br />

整 型 复 杂 表 达 式 的 值 只 能 强 制 转 换 到 更 窄 的 类 型 且 与 表 达 式 的 基 本 类<br />

型 具 有 相 同 的 符 号 。<br />

规 则 10.4( 强 制 ): 浮 点 类 型 复 杂 表 达 式 的 值 只 能 强 制 转 换 到 更 窄 的 浮 点 类 型 。<br />

如 果 强 制 转 换 要 用 在 任 何 复 杂 表 达 式 上 , 可 以 应 用 的 转 换 的 类 型 应 该 严 格 限 制 。 如 6.10<br />

节 所 阐 释 的 , 复 杂 表 达 式 的 转 换 经 常 是 混 淆 的 来 源 , 保 持 谨 慎 是 明 智 的 做 法 。 为 了 符 合 这 些<br />

规 则 , 有 必 要 使 用 临 时 变 量 并 引 进 附 加 的 语 句 。<br />

… (float32_t) (f64a + f64b) /* compliant */<br />

… (float64_t) (f32a + f32b) /* not compliant */<br />

… (float64_t) f32a /* compliant */<br />

… (float64_t) (s32a / s32b) /* not compliant */<br />

… (float64_t) (s32a > s32b) /* not compliant */<br />

… (float64_t) s32a / (float32_t) s32b /* compliant */<br />

… (uint32_t) (u16a + u16b) /* not compliant */<br />

… (uint32_t) u16a + u16b /* compliant */<br />

... (uint32_t) u16a + (uint32_t) u16b /* compliant */<br />

... (int16_t) (s32a – 12345) /* compliant */<br />

... (uint8_t) (u16a * u16b) /* compliant */<br />

... (uint16_t) (u8a * u8b) /* not compliant */<br />

... (int16_t) (s32a * s32b) /* compliant */<br />

... (int32_t) (s16a * s16b) /* not compliant */<br />

… (uint16_t) (f64a + f64b) /* not compliant */<br />

… (float32_t) (u16a + u16b) /* not compliant */<br />

… (float64_t) foo1 (u16a + u16b) /* compliant */<br />

… (int32_t) buf16a[u16a + u16b] /* compliant */<br />

规 则 10.5( 强 制 ):<br />

如 果 位 运 算 符 ~ 和 > 4; /* compliant */<br />

result_16 = ( ( uint16_t ) (~(uint16_t) port ) ) >> 4 ; /* compliant */<br />

35


当 6 ; /* not compliant */<br />

result_16 的 值 将 依 赖 于 int 实 现 的 大 小 。 附 加 的 强 制 转 换 可 以 避 免 任 何 模 糊 性 。<br />

result_16 = ( ( uint16_t ) ( ( uint16_t ) port > 6 ; /* compliant */<br />

6.10.8 整 数 后 缀<br />

规 则 10.6( 强 制 ): 后 缀 “U” 应 该 用 在 所 有 unsigned 类 型 的 常 量 上 。<br />

整 型 常 量 的 类 型 是 混 淆 的 潜 在 来 源 , 因 为 它 依 赖 于 许 多 因 素 的 复 杂 组 合 , 包 括 :<br />

• 常 数 的 量 级<br />

• 整 数 类 型 实 现 的 大 小<br />

• 任 何 后 缀 的 存 在<br />

• 数 值 表 达 的 进 制 ( 即 十 进 制 、 八 进 制 或 十 六 进 制 )<br />

例 如 , 整 型 常 量 “40000” 在 32 位 环 境 中 是 int 类 型 , 而 在 16 位 环 境 中 则 是 long 类 型 。<br />

值 0x8000 在 16 位 环 境 中 是 unsigned int 类 型 , 而 在 32 位 环 境 中 则 是 (signed)int 类 型 。<br />

但 是 :<br />

注 意 :<br />

• 任 何 带 有 “U” 后 缀 的 值 是 unsigned 类 型<br />

• 一 个 不 带 后 缀 的 小 于 2 31 的 十 进 制 值 是 signed 类 型<br />

• 不 带 后 缀 的 大 于 或 等 于 2 15 的 十 六 进 制 数 可 能 是 signed 或 unsigned 类 型<br />

• 不 带 后 缀 的 大 于 或 等 于 2 31 的 十 进 制 数 可 能 是 signed 或 unsigned 类 型<br />

常 量 的 符 号 应 该 明 确 。 符 号 的 一 致 性 是 构 建 良 好 形 式 的 表 达 式 的 重 要 原 则 。 如 果 一 个 常<br />

数 是 unsigned 类 型 , 为 其 加 上 “U” 后 缀 将 有 助 于 避 免 混 淆 。 当 用 在 较 大 数 值 上 时 , 后 缀 也 许<br />

是 多 余 的 ( 在 某 种 意 义 上 它 不 会 影 响 常 量 的 类 型 ); 然 而 后 缀 的 存 在 对 代 码 的 清 晰 性 是 种 有 价<br />

值 的 帮 助 。<br />

6.11 指 针 类 型 转 换<br />

指 针 类 型 可 以 归 为 如 下 几 类 :<br />

• 对 象 指 针<br />

• 函 数 指 针<br />

• void 指 针<br />

• 空 (null) 指 针 常 量 ( 即 由 数 值 0 强 制 转 换 为 void* 类 型 )<br />

涉 及 指 针 类 型 的 转 换 需 要 明 确 的 强 制 , 除 非 在 以 下 时 刻 :<br />

• 转 换 发 生 在 对 象 指 针 和 void 指 针 之 间 , 而 且 目 标 类 型 承 载 了 源 类 型 的 所 有 类 型 标 识<br />

符<br />

• 当 空 指 针 常 量 (void*) 被 赋 值 给 任 何 类 型 的 指 针 或 与 其 做 等 值 比 较 时 , 空 指 针 常 量<br />

被 自 动 转 化 为 特 定 的 指 针 类 型<br />

C 当 中 只 定 义 了 一 些 特 定 的 指 针 类 型 转 换 , 而 一 些 转 换 的 行 为 是 实 现 定 义 的 。<br />

规 则 11.1( 强 制 ): 转 换 不 能 发 生 在 函 数 指 针 和 其 他 除 了 整 型 之 外 的 任 何 类 型 指 针 之 间 。<br />

36


[ 未 定 义 27、28]<br />

函 数 指 针 到 不 同 类 型 指 针 的 转 换 会 导 致 未 定 义 的 行 为 。 举 个 例 子 , 这 意 味 着 一 个 函 数 指<br />

针 不 能 转 换 成 指 向 不 同 类 型 函 数 的 指 针 。<br />

规 则 11.2( 强 制 ):<br />

这 些 转 换 未 经 定 义 。<br />

规 则 11.3( 建 议 ):<br />

对 象 指 针 和 其 他 除 整 型 之 外 的 任 何 类 型 指 针 之 间 、 对 象 指 针 和 其 他 类<br />

型 对 象 的 指 针 之 间 、 对 象 指 针 和 void 指 针 之 间 不 能 进 行 转 换 。<br />

不 应 在 指 针 类 型 和 整 型 之 间 进 行 强 制 转 换<br />

[ 未 定 义 29]<br />

[ 实 现 24]<br />

当 指 针 转 换 到 整 型 时 所 需 要 的 整 型 的 大 小 是 实 现 定 义 的 。 尽 可 能 的 情 况 下 要 避 免 指 针 和<br />

整 型 之 间 的 转 换 , 但 是 在 访 问 内 存 映 射 寄 存 器 或 其 他 硬 件 特 性 时 这 是 不 可 避 免 的 。<br />

规 则 11.4( 建 议 ): 不 应 在 某 类 型 对 象 指 针 和 其 他 不 同 类 型 对 象 指 针 之 间 进 行 强 制 转 换 。<br />

如 果 新 的 指 针 类 型 需 要 更 严 格 的 分 配 时 这 样 的 转 换 可 能 是 无 效 的 。<br />

uint8_t * p1;<br />

uint32_t * p2;<br />

p2 = (uint32_t *) p1; /* Imcompatible alignment ? */<br />

规 则 11.5( 强 制 ):<br />

如 果 指 针 所 指 向 的 类 型 带 有 const 或 volatile 限 定 符 , 那 么 移 除 限 定 符<br />

的 强 制 转 换 是 不 允 许 的 。<br />

[ 未 定 义 39、40]<br />

任 何 通 过 强 制 转 换 移 除 类 型 限 定 符 的 企 图 都 是 对 类 型 限 定 符 规 则 的 违 背 。 注 意 , 这 里 所<br />

指 的 限 定 符 与 任 何 可 以 应 用 在 指 针 本 身 的 限 定 符 不 同 。<br />

uint16_t x;<br />

uint16_t * const cpi = &x; /* const pointer */<br />

uint16_t * const * pcpi ; /* pointer to const pointer */<br />

const uint16_t * * ppci ; /* pointer to pointer to const */<br />

uint16_t * * ppi;<br />

const uint16_t * pci; /* pointer to const */<br />

volatile uint16_t * pvi; /* pointer to volatile */<br />

uint16_t * pi;<br />

…<br />

pi = cpi;<br />

/* Compliant – no conversion<br />

no cast required */<br />

pi = (uint16_t *)pci; /* Not compliant */<br />

pi = (uint16_t *)pvi ; /* Not compliant */<br />

ppi = (uint16_t *)pcpi ; /* Not compliant */<br />

ppi = (uint16_t *)ppci ; /* Not compliant */<br />

6.12 表 达 式<br />

规 则 12.1( 建 议 ): 不 要 过 分 依 赖 C 表 达 式 中 的 运 算 符 优 先 规 则<br />

括 号 的 使 用 除 了 可 以 覆 盖 缺 省 的 运 算 符 优 先 级 以 外 , 还 可 以 用 来 强 调 所 使 用 的 运 算 符 。<br />

37


使 用 相 当 复 杂 的 C 运 算 符 优 先 级 规 则 很 容 易 引 起 错 误 , 那 么 这 种 方 法 就 可 以 帮 助 避 免 这 样 的<br />

错 误 , 并 且 可 以 使 得 代 码 更 为 清 晰 可 读 。 然 而 , 过 多 的 括 号 会 分 散 代 码 使 其 降 低 了 可 读 性 。<br />

下 面 的 方 针 给 出 了 何 时 使 用 括 号 的 建 议 :<br />

• 赋 值 运 算 符 的 右 手 操 作 数 不 需 要 使 用 括 号 , 除 非 右 手 端 本 身 包 含 了 赋 值 表 达 式 :<br />

x = a + b; /* acceptable */<br />

x = (a + b); /* ( ) not required */<br />

• 一 元 运 算 符 的 操 作 数 不 需 要 使 用 括 号 :<br />

x = a * -1; /* acceptable */<br />

x = a * (-1); /* ( ) not required */<br />

• 否 则 , 二 元 和 三 元 运 算 符 的 操 作 数 应 该 是 cast-expressions( 见 6.3.4 节 ISO 9899:1990<br />

[2]), 除 非 表 达 式 中 所 有 运 算 符 是 相 同 的 。<br />

x = a + b + c; /* acceptable, but care needed */<br />

x = f ( a + b, c ); /* no ( ) required for a + b */<br />

x = ( a == b ) ? a : ( a – b );<br />

if (a && b && c) /* acceptable */<br />

x = (a + b) – (c + d);<br />

x = (a * 3) + c + d;<br />

x = (uint16_t) a + b; /* no need for ( ( uint16_t ) a ) */<br />

• 即 使 所 有 运 算 符 都 是 相 同 的 , 也 可 以 使 用 括 号 控 制 运 算 的 次 序 。 某 些 运 算 符 ( 如 ,<br />

加 法 和 乘 法 ) 在 代 数 学 上 结 合 律 的 , 而 在 C 中 未 必 如 此 。 类 似 地 , 涉 及 混 合 类 型 的<br />

整 数 运 算 ( 许 多 规 则 不 允 许 ) 因 为 整 数 提 升 的 存 在 可 以 产 生 不 同 的 结 果 。 下 面 的 例<br />

子 是 按 照 16 位 的 实 现 写 成 的 , 它 描 述 了 加 法 不 是 结 合 的 以 及 表 达 式 结 构 清 晰 的 重 要<br />

性 :<br />

uint16_t a = 10;<br />

uint16_t b = 65535;<br />

uint32_t c = 0;<br />

uint32_t d;<br />

d = (a + b) + c; /* d is 9; a + b wraps modulo 65536 */<br />

d = a + (b + c); /* d is 65545 */<br />

/* this example also deviates from several other rules */<br />

注 意 , 规 则 12.5 是 本 规 则 的 特 例 , 它 只 能 应 用 在 逻 辑 运 算 符 (&& 和 | |) 上 。<br />

规 则 12.2( 强 制 ): 表 达 式 的 值 在 标 准 所 允 许 的 任 何 运 算 次 序 下 都 应 该 是 相 同 的 。<br />

[ 未 指 定 7-9; 未 定 义 18]<br />

除 了 少 数 运 算 符 ( 特 别 地 , 函 数 调 用 运 算 符 ( )、&&、| |、? : 和 , ( 逗 号 ) ) 之 外 , 子<br />

表 达 式 所 依 据 的 运 算 次 序 是 未 指 定 的 并 会 随 时 更 改 。 这 意 味 着 不 能 信 任 子 表 达 式 的 运 算 次 序 ,<br />

特 别 不 能 信 任 可 能 会 发 生 副 作 用 (side effect) 的 运 算 次 序 。 在 表 达 式 运 算 中 的 某 些 点 上 , 如<br />

果 能 保 证 所 有 先 前 的 副 作 用 都 已 经 发 生 , 那 么 这 些 点 称 为 “ 序 列 点 (sequence point)”。 序 列 点<br />

和 副 作 用 的 描 述 见 ISO 9899:1990 [2] 的 5.1.2.3 节 、6.3 节 和 6.6 节 。<br />

注 意 , 运 算 次 序 的 问 题 不 能 使 用 括 号 来 解 决 , 因 为 这 不 是 优 先 级 的 问 题 。<br />

下 面 的 条 款 告 诉 我 们 对 运 算 次 序 的 依 赖 是 如 何 发 生 的 , 并 由 此 帮 助 我 们 采 纳 本 规 则 。<br />

• 自 增 或 自 减 运 算 符<br />

38


做 为 能 产 生 错 误 的 例 子 , 考 虑<br />

x = b[i] + i++;<br />

根 据 b[i] 的 运 算 是 先 于 还 是 后 于 i ++ 的 运 算 , 表 达 式 会 产 生 不 同 的 结 果 。 把 增 值<br />

运 算 做 为 单 独 的 语 句 , 可 以 避 免 这 个 问 题 。 那 么 :<br />

• 函 数 参 数<br />

x = b[i] + i;<br />

i ++;<br />

函 数 参 数 的 运 算 次 序 是 未 指 定 的 。<br />

x = func ( i++, i);<br />

根 据 函 数 的 两 个 参 数 的 运 算 次 序 不 同 , 表 达 式 会 给 出 不 同 的 结 果 。<br />

• 函 数 指 针<br />

如 果 函 数 是 通 过 函 数 指 针 调 用 的 , 那 么 函 数 标 识 符 和 函 数 参 数 运 算 次 序 是 不 可 信 任<br />

的 。<br />

• 函 数 调 用<br />

p->task_start_fn (p++);<br />

函 数 在 被 调 用 时 可 以 具 有 附 加 的 作 用 ( 如 , 修 改 某 些 全 局 数 据 )。 可 以 通 过 在 使 用 函<br />

数 的 表 达 式 之 前 调 用 函 数 并 为 值 采 用 临 时 变 量 的 方 法 避 免 对 运 算 次 序 的 依 赖 。<br />

例 如<br />

x = f (a) + g (a);<br />

可 以 写 成<br />

x = f (a);<br />

x += g (a);<br />

做 为 可 以 产 生 错 误 的 例 子 , 考 虑 下 面 的 表 达 式 , 它 从 堆 栈 中 取 出 两 个 值 , 从 第 一 个<br />

值 中 减 去 第 二 个 值 , 再 把 结 果 放 回 栈 中 :<br />

push ( pop () – pop () );<br />

根 据 哪 一 个 pop () 函 数 先 进 行 计 算 ( 因 为 pop() 具 有 副 作 用 ) 会 产 生 不 同 的 结 果 。<br />

• 嵌 套 的 赋 值 语 句<br />

表 达 式 中 嵌 套 的 赋 值 可 以 产 生 附 加 的 副 作 用 。 不 给 这 种 能 导 致 对 运 算 次 序 的 依 赖 提<br />

供 任 何 机 会 的 最 好 做 法 是 , 不 要 在 表 达 式 中 嵌 套 赋 值 语 句 。<br />

例 如 , 下 面 的 做 法 是 不 赞 成 的 :<br />

x = y = y = z / 3;<br />

x = y = y++;<br />

• volatile 访 问<br />

类 型 限 定 符 volatile 是 C 提 供 的 , 用 来 表 示 那 些 其 值 可 以 独 立 于 程 序 的 运 行 而 自 由 更<br />

改 的 对 象 ( 例 如 输 入 寄 存 器 )。 对 带 有 volatile 限 定 类 型 的 对 象 的 访 问 可 能 改 变 它 的<br />

值 。C 编 译 器 不 会 优 化 对 volatile 的 读 取 , 而 且 , 据 C 程 序 所 关 心 的 , 对 volatile 的<br />

读 取 具 有 副 作 用 ( 改 变 volatile 的 值 )。<br />

做 为 表 达 式 的 一 部 分 通 常 需 要 访 问 volatile 数 据 , 这 意 味 着 对 运 算 次 序 的 依 赖 。 建 议<br />

对 volatile 的 访 问 尽 可 能 地 放 在 简 单 的 赋 值 语 句 中 , 如 :<br />

volatile uint16_t v;<br />

39


* … */<br />

x = v;<br />

本 规 则 讨 论 了 带 有 副 作 用 的 运 算 次 序 问 题 。 要 注 意 子 表 达 式 的 运 算 次 数 同 样 会 带 来 问 题 ,<br />

本 规 则 没 有 提 及 。 这 是 函 数 调 用 的 问 题 , 其 中 函 数 是 以 宏 实 现 的 。 例 如 , 考 虑 下 面 的 函 数 宏<br />

及 其 调 用 :<br />

#define MAX (a, b) ( ( (a) > (b) ) ? (a) : (b) )<br />

/* … */<br />

z = MAX (i++, j);<br />

当 a > b 时 , 该 定 义 计 算 了 两 次 第 一 个 参 数 而 在 a


以 导 致 函 数 所 运 行 的 环 境 状 态 的 改 变 。<br />

规 则 12.5( 强 制 ):<br />

逻 辑 && 或 | | 的 操 作 数 应 该 是 primary-expressions。<br />

“Primary expressions” 定 义 在 ISO 9899:1990 [2] 的 6.3.1 节 中 。 本 质 上 它 们 或 是 单 一 的 标<br />

识 符 , 或 是 常 量 , 或 是 括 号 括 起 来 的 表 达 式 。 本 规 则 的 作 用 是 要 求 , 如 果 操 作 数 不 是 单 一 的<br />

标 识 符 或 常 量 , 那 么 它 必 须 被 括 起 来 。 在 这 种 情 况 下 , 括 号 对 于 代 码 的 可 读 性 和 确 保 预 期 的<br />

行 为 都 是 非 常 重 要 的 。 如 果 表 达 式 只 由 逻 辑 && 序 列 组 成 或 逻 辑 | | 序 列 组 成 , 就 不 需 要 使<br />

用 括 号 。<br />

例 如 :<br />

if ( ( x == 0 ) && ishigh ) /* make x == 0 primary */<br />

if ( x || y || z ) /* exception allowed, if x, y and z are Boolean */<br />

if ( x || ( y && z ) ) /* make y && z primary */<br />

if ( x && ( !y ) ) /* make !y primary */<br />

if ( ( is_odd (y) ) && x ) /* make call primary */<br />

如 果 表 达 式 只 由 逻 辑 && 序 列 组 成 或 逻 辑 | | 序 列 组 成 , 就 不 需 要 使 用 括 号 。<br />

if ( ( x > c1 ) && ( y > c2 ) && ( z > c3 ) ) /* compliant */<br />

if ( ( x > c1 ) && ( y > c2 ) || (z > c3 ) ) /* not compliant */<br />

if ( ( x > c1 ) && ( ( y > c2 ) || ( z > c3 ) ) ) /* compliant extra ( ) used */<br />

注 意 , 本 规 则 是 规 则 12.1 的 特 例 。<br />

规 则 12.6( 建 议 ):<br />

逻 辑 运 算 符 (&&、| | 和 !) 的 操 作 数 应 该 是 有 效 的 布 尔 数 。 有 效 布 尔<br />

类 型 的 表 达 式 不 能 用 做 非 逻 辑 运 算 符 (&&、| | 和 !) 的 操 作 数<br />

[Koenig 48]<br />

逻 辑 运 算 符 &&、| | 和 ! 很 容 易 同 位 运 算 符 &、| 和 ~ 混 淆 。 见 术 语 表 中 的 “Boolean<br />

expressions”。<br />

规 则 12.7( 强 制 ): 位 运 算 符 不 能 用 于 基 本 类 型 (underlying type) 是 有 符 号 的 操 作 数 上 。<br />

[ 实 现 17-19]<br />

位 运 算 (~、、&、^ 和 | ) 对 有 符 号 整 数 通 常 是 无 意 义 的 。 比 如 , 如 果 右 移 运 算<br />

把 符 号 位 移 动 到 数 据 位 上 或 者 左 移 运 算 把 数 据 位 移 动 到 符 号 位 上 , 就 会 产 生 问 题 。<br />

基 本 类 型 的 描 述 见 6.10 节 。<br />

规 则 12.8( 强 制 ):<br />

移 位 运 算 符 的 右 手 操 作 数 应 该 位 于 零 和 某 数 之 间 , 这 个 数 要 小 于 左 手<br />

操 作 数 的 基 本 类 型 的 位 宽 。<br />

[ 未 定 义 32]<br />

例 如 , 如 果 左 移 或 右 移 运 算 的 左 手 操 作 数 是 16 位 整 型 , 那 么 要 确 保 它 移 动 的 位 数 位 于 0<br />

和 15 之 间 。<br />

基 本 类 型 的 描 述 见 节 6.10。<br />

有 多 种 确 保 遵 循 本 规 则 的 方 法 。 对 右 手 操 作 数 来 说 , 最 简 单 的 是 使 其 为 一 个 常 数 ( 其 值<br />

可 以 静 态 检 查 )。 使 用 无 符 号 整 型 可 以 保 证 该 操 作 数 非 负 , 那 么 只 有 其 上 限 需 要 检 查 ( 在 运 行<br />

时 动 态 检 查 或 者 通 过 代 码 复 查 )。 否 则 这 两 种 限 制 都 要 被 检 查 。<br />

u8a = (uint8_t) (u8a


把 一 元 减 运 算 符 用 在 基 本 类 型 为 unsigned int 或 unsigned long 的 表 达 式 上 时 , 会 分 别 产 生<br />

类 型 为 unsigned int 或 unsigned long 的 结 果 , 这 是 无 意 义 的 操 作 。 把 一 元 减 运 算 符 用 在 无 符 号<br />

短 整 型 的 操 作 数 上 , 根 据 整 数 提 升 的 作 用 它 可 以 产 生 有 意 义 的 有 符 号 结 果 , 但 这 不 是 好 的 方<br />

法 。<br />

基 本 类 型 的 描 述 见 节 6.10。<br />

规 则 12.10( 强 制 ): 不 要 使 用 逗 号 运 算 符 。<br />

使 用 逗 号 运 算 符 通 常 不 利 于 代 码 的 可 读 性 , 可 以 使 用 其 他 方 法 达 到 相 同 的 效 果 。<br />

规 则 12.11( 建 议 ):<br />

无 符 号 整 型 常 量 表 达 式 的 计 算 不 应 产 生 折 叠 (wrap-around)。<br />

因 为 无 符 号 整 型 表 达 式 不 会 严 格 意 义 上 地 溢 出 , 但 会 以 模 的 方 式 产 生 折 叠 , 因 此 任 何 无<br />

符 号 整 型 常 量 表 达 式 的 有 效 “ 溢 出 ” 将 不 会 被 编 译 器 检 测 到 。 尽 管 在 运 行 时 (run-time) 有 很<br />

好 的 理 由 依 赖 由 无 符 号 整 型 提 供 的 模 运 算 , 但 在 编 译 时 (compile-time) 计 算 常 量 表 达 式 该 理<br />

由 就 不 那 么 明 显 了 。 因 此 任 何 发 生 折 叠 的 无 符 号 整 型 常 量 表 达 式 都 可 能 表 示 编 程 错 误 。<br />

本 规 则 同 等 地 应 用 于 翻 译 过 程 的 所 有 阶 段 。 对 于 在 编 译 时 计 算 所 选 择 的 常 量 表 达 式 , 编<br />

译 器 以 这 样 的 方 式 计 算 , 即 其 计 算 结 果 与 在 目 标 机 上 的 运 算 结 果 相 同 , 除 了 条 件 预 处 理 指 令 。<br />

对 这 样 的 指 令 , 可 以 使 用 常 见 的 算 术 运 算 法 则 ( 见 ISO 9899:1990 [2] 中 6.4 节 ), 但 是 int 和<br />

unsigned int 的 行 为 会 被 分 别 替 代 成 好 像 它 们 是 long 或 unsigned long 一 样 。<br />

例 如 , 在 int 类 型 为 16 位 、long 类 型 为 32 位 的 机 器 上 :<br />

#define START 0x8000<br />

#define END 0xFFFF<br />

#define LEN 0x8000<br />

#if ( (START + LEN ) > END )<br />

#error Buffer Overrun /* OK because START and LEN are unsigned long */<br />

#endif<br />

#if ( ( ( END – START ) – LEN ) < 0 )<br />

#error Buffer Overrun<br />

/* Not OK: subtraction result wraps around to 0xFFFFFFFF */<br />

#endif<br />

/* contrast the above START + LEN with the following */<br />

if ( ( START + LEN ) > END )<br />

{<br />

error ( “Buffer overrun “ );<br />

/* Not OK: START + LEN wraps around to 0x0000 due to<br />

unsigned<br />

int arithmetic */<br />

}<br />

规 则 12.12( 强 制 ): 不 应 使 用 浮 点 数 的 基 本 (underlying) 的 位 表 示 法 (bit representation)<br />

[ 未 指 定 6; 实 现 20]<br />

浮 点 数 的 存 储 方 法 可 以 根 据 编 译 器 的 不 同 而 不 同 , 因 此 不 应 使 用 直 接 依 赖 于 存 储 方 法 的<br />

浮 点 操 作 。 应 该 使 用 内 置 (in-built) 的 运 算 符 和 函 数 , 它 们 对 程 序 员 隐 藏 了 存 储 细 节 。<br />

规 则 12.13( 建 议 ): 在 一 个 表 达 式 中 , 自 增 (++) 和 自 减 (- -) 运 算 符 不 应 同 其 他 运 算 符<br />

混 合 在 一 起 。<br />

不 建 议 使 用 同 其 他 算 术 运 算 符 混 合 在 一 起 的 自 增 和 自 减 运 算 符 , 是 因 为 :<br />

42


• 它 显 著 削 弱 了 代 码 的 可 读 性<br />

• 它 为 语 句 引 入 了 其 他 的 副 作 用 , 可 能 存 在 未 定 义 的 行 为<br />

把 这 些 操 作 同 其 他 算 术 操 作 隔 离 开 是 比 较 安 全 的 。<br />

例 如 , 下 面 的 语 句 是 不 适 合 的 :<br />

u8a = ++u8b + u8c--; /* Not compliant */<br />

下 面 的 序 列 更 为 清 晰 和 安 全 :<br />

++u8b;<br />

u8a = u8b + u8c;<br />

u8c --;<br />

6.13 控 制 语 句 表 达 式<br />

规 则 13.1( 强 制 ): 赋 值 运 算 符 不 能 使 用 在 产 生 布 尔 值 的 表 达 式 上 。<br />

[Koenig 6]<br />

任 何 被 认 为 是 具 有 布 尔 值 的 表 达 式 上 都 不 能 使 用 赋 值 运 算 。 这 排 除 了 赋 值 运 算 符 的 简 单<br />

与 复 杂 的 使 用 形 式 , 其 操 作 数 是 具 有 布 尔 值 的 表 达 式 。 然 而 , 它 不 排 除 把 布 尔 值 赋 给 变 量 的<br />

操 作 。<br />

如 果 布 尔 值 表 达 式 需 要 赋 值 操 作 , 那 么 赋 值 操 作 必 须 在 操 作 数 之 外 分 别 进 行 。 这 可 以 帮<br />

助 避 免 “=” 和 “= =” 的 混 淆 , 帮 助 我 们 静 态 地 检 查 错 误 。<br />

见 术 语 表 中 的 “Boolean expressions”。<br />

例 如 :<br />

x = y;<br />

if (x != 0)<br />

{<br />

foo ();<br />

}<br />

不 能 写 成 :<br />

if ( ( x = y ) != 0 ) /* Boolean by context */<br />

{<br />

foo ();<br />

}<br />

或 者 更 坏 的 :<br />

if (x = y)<br />

{<br />

foo ();<br />

}<br />

规 则 13.2( 建 议 ): 数 的 非 零 检 测 应 该 明 确 给 出 , 除 非 操 作 数 是 有 效 的 布 尔 类 型 。<br />

当 要 检 测 一 个 数 据 不 等 于 零 时 , 该 测 试 要 明 确 给 出 。 本 规 则 的 例 外 是 该 数 据 代 表 布 尔 类<br />

型 的 值 , 虽 然 在 C 中 布 尔 数 实 际 上 也 是 整 数 。 本 规 则 的 着 眼 点 是 在 代 码 的 清 晰 上 , 给 出 整 数<br />

和 逻 辑 数 之 间 的 清 晰 划 分 。<br />

43


例 如 , 如 果 x 是 个 整 数 , 那 么 :<br />

if ( x != 0) /* Correct way of testing x is non-zero */<br />

if ( y ) /* Not compliant, unless y is effectively Boolean data (e.g. a flag). */<br />

见 术 语 表 中 的 “Boolean expressions”。<br />

规 则 13.3( 强 制 ): 浮 点 表 达 式 不 能 做 相 等 或 不 等 的 检 测 。<br />

这 是 浮 点 类 型 的 固 有 特 性 , 等 值 比 较 通 常 不 会 计 算 为 true, 即 使 期 望 如 此 。 而 且 , 这 种 比<br />

较 行 为 不 能 在 执 行 前 做 出 预 测 , 它 会 随 着 实 现 的 改 变 而 改 变 。 例 如 , 下 面 代 码 中 的 测 试 结 果<br />

就 是 不 可 预 期 的 :<br />

float32_t x, y;<br />

/* some calculations in here */<br />

if ( x == y) /* not compliant */<br />

{ /* … */ }<br />

if (x == 0.0f) /* not compliant */<br />

间 接 的 检 测 同 样 是 有 问 题 的 , 在 本 规 则 内 也 是 禁 止 的 。 例 如 :<br />

if ( ( x = y ) )<br />

{ /* … */ }<br />

为 了 获 得 确 定 的 浮 点 比 较 , 建 议 写 一 个 实 现 比 较 运 算 的 库 。 这 个 库 应 该 考 虑 浮 点 的 粒 度<br />

(FLT_EPSILON) 以 及 参 与 比 较 的 数 的 量 级 。 见 规 则 13.4 和 规 则 20.3。<br />

规 则 13.4( 强 制 ): for 语 句 的 控 制 表 达 式 不 能 包 含 任 何 浮 点 类 型 的 对 象 。<br />

控 制 表 达 式 可 能 会 包 含 一 个 循 环 计 数 器 , 检 测 其 值 以 决 定 循 环 的 终 止 。 浮 点 变 量 不 能 用<br />

于 此 目 的 。 舍 入 误 差 和 截 取 误 差 会 通 过 循 环 的 迭 代 过 程 传 播 , 导 致 循 环 变 量 的 显 著 误 差 , 并<br />

且 在 进 行 检 测 时 很 可 能 给 出 不 可 预 期 的 结 果 。 例 如 , 循 环 执 行 的 次 数 可 以 随 着 实 现 的 改 变 而<br />

改 变 , 也 是 不 可 预 测 的 。 见 规 则 13.3。<br />

规 则 13.5( 强 制 ): for 语 句 的 三 个 表 达 式 应 该 只 关 注 循 环 控 制 。<br />

for 语 句 的 三 个 表 达 式 都 给 出 时 它 们 应 该 只 用 于 如 下 目 的 :<br />

第 一 个 表 达 式 初 始 化 循 环 计 数 器 ( 例 子 中 的 i)<br />

第 二 个 表 达 式<br />

第 三 个 表 达 式<br />

应 该 包 含 对 循 环 计 数 器 (i) 和 其 他 可 选 的 循 环 控 制 变 量 的 测 试<br />

循 环 计 数 器 (i) 的 递 增 或 递 减<br />

规 则 13.6( 强 制 ): for 循 环 中 用 于 迭 代 计 数 的 数 值 变 量 不 应 在 循 环 体 中 修 改 。<br />

不 能 在 循 环 体 中 修 改 循 环 计 数 器 。 然 而 可 以 修 改 表 现 为 逻 辑 数 值 的 其 他 循 环 控 制 变 量 。<br />

例 如 , 指 示 某 些 事 情 已 经 完 成 的 标 记 , 然 后 在 for 语 句 中 测 试 。<br />

flag = 1;<br />

for ( i = 0; ( i < 5 ) && (flag == 1 ); i++)<br />

{<br />

/* … */<br />

flage = 0; /* Compliant – allows early termination of loop */<br />

i = i + 3; /* Not compliant – altering the loop counter */<br />

}<br />

规 则 13.7( 强 制 ): 不 允 许 进 行 结 果 不 会 改 变 的 布 尔 运 算 。<br />

如 果 布 尔 运 算 产 生 的 结 果 始 终 为 “true” 或 始 终 为 “false”, 那 么 这 很 可 能 是 编 程 错 误 。<br />

44


6.14 控 制 流<br />

enum ec { RED, BLUE, GREEN } col;<br />

…<br />

if (u16a < 0) /* Not compliant – u16a is always >= 0 */<br />

…<br />

if (u16a 20) ) /* Not compliant – always false */<br />

…<br />

if ( ( s8a < 10 ) || ( s8a > 5) ) /* Not compliant – always true */<br />

…<br />

if ( col 10)<br />

{<br />

if (s8a > 5) /* Not compliant – s8a is not volatile */<br />

{<br />

}<br />

}<br />

规 则 14.1( 强 制 ): 不 能 有 不 可 到 达 (unreachable) 的 代 码 。<br />

本 规 则 是 针 对 那 些 在 任 何 环 境 中 都 不 能 到 达 的 代 码 , 这 些 代 码 在 编 译 时 就 能 被 标 识 出 不<br />

可 到 达 。 规 则 排 除 了 可 以 到 达 但 永 远 不 会 执 行 的 代 码 ( 如 , 保 护 性 编 程 代 码 (defensive<br />

programming) )。<br />

如 果 从 相 关 的 入 口 到 某 部 分 代 码 之 间 不 存 在 控 制 流 路 径 , 那 么 这 部 分 代 码 就 是 不 可 到 达<br />

的 。 例 如 , 在 无 条 件 控 制 转 移 代 码 后 的 未 标 记 代 码 就 是 不 可 到 达 的 :<br />

switch ( event )<br />

{<br />

case E_wakeup:<br />

do_wakeup ();<br />

break; /* unconditional control transfer */<br />

do_more (); /* Not compliant – unreachable code */<br />

/* … */<br />

default:<br />

/* … */<br />

break;<br />

}<br />

对 整 个 函 数 来 说 , 如 果 不 存 在 调 用 它 的 手 段 , 那 么 这 个 函 数 将 是 不 可 到 达 的 。<br />

45


规 则 14.2( 强 制 ): 所 有 非 空 语 句 (non-null statement) 应 该 :<br />

a) 不 管 怎 样 执 行 都 至 少 有 一 个 副 作 用 (side-effect), 或 者<br />

b) 可 以 引 起 控 制 流 的 转 移<br />

任 何 语 句 ( 非 空 语 句 ), 如 果 既 没 有 副 作 用 也 不 引 起 控 制 流 的 改 变 , 通 常 就 会 指 示 出 编 程<br />

错 误 , 因 此 要 进 行 对 这 样 语 句 的 静 态 检 测 。 例 如 , 下 面 的 语 句 在 执 行 时 不 一 定 带 有 副 作 用 :<br />

/* assume uint16_t x;<br />

and uint16_t i; */<br />

…<br />

x >= 3u; /* not compliant: x is compared to 3,<br />

and the answer is discarded */<br />

注 :“null statement” 和 “side effect” 分 别 定 义 在 ISO 9899:1990 [2] 中 节 6.6.3 和 5.1.2.3。<br />

规 则 14.3( 强 制 ):<br />

在 预 处 理 之 前 , 空 语 句 只 能 出 现 在 一 行 上 ; 其 后 可 以 跟 有 注 释 , 假 设<br />

紧 跟 空 语 句 的 第 一 个 字 符 是 空 格 。<br />

通 常 不 会 故 意 包 含 空 语 句 , 但 是 在 使 用 它 们 的 地 方 , 它 们 应 该 出 现 在 它 们 本 身 的 行 上 。<br />

空 语 句 前 面 可 以 有 空 格 以 保 持 缩 进 的 格 式 。 如 果 一 条 注 释 跟 在 空 语 句 的 后 面 , 那 么 至 少 要 有<br />

一 个 空 格 把 空 语 句 和 注 释 分 隔 开 来 。 需 要 这 样 起 分 隔 作 用 的 空 格 是 因 为 它 给 读 者 提 供 了 重 要<br />

的 视 觉 信 息 。 遵 循 本 规 则 使 得 静 态 检 查 工 具 能 够 为 与 其 他 文 本 出 现 在 一 行 上 的 空 语 句 提 出 警<br />

告 , 因 为 这 样 的 情 形 通 常 表 示 编 程 错 误 。 例 如 :<br />

while ( ( port & 0x80 ) == 0 )<br />

{<br />

; /* wait for pin – Compliant */<br />

/* wait for pin */ ; /* Not compliant, comment before ; */<br />

;/* wait for pin – Not compliant, no white-space char after ; */<br />

}<br />

规 则 14.4( 强 制 ): 不 应 使 用 goto 语 句 。<br />

规 则 14.5( 强 制 ): 不 应 使 用 continue 语 句 。<br />

规 则 14.6( 强 制 ): 对 任 何 迭 代 语 句 至 多 只 应 有 一 条 break 语 句 用 于 循 环 的 结 束 。<br />

这 些 规 则 关 心 的 是 良 好 的 编 程 结 构 。 循 环 中 允 许 有 一 条 break 语 句 , 因 为 这 允 许 双 重 结 果<br />

的 循 环 或 代 码 优 化 。<br />

规 则 14.7( 强 制 ): 一 个 函 数 在 其 结 尾 应 该 有 单 一 的 退 出 点 。<br />

这 是 由 IEC 61508 良 好 的 编 程 格 式 要 求 的 。<br />

规 则 14.8( 强 制 ): 组 成 switch、while、do...while 或 for 结 构 体 的 语 句 应 该 是 复 合 语 句 。<br />

组 成 switch 语 句 或 while、do ... while 或 for 循 环 结 构 体 的 语 句 应 该 是 复 合 语 句 ( 括 在 大 括<br />

号 里 ), 即 使 该 复 合 语 句 只 包 含 一 条 语 句 。<br />

例 如 :<br />

for ( i = 0 ; i < N_ELEMENTS ; ++i )<br />

{<br />

buffer[i] = 0; /* Even a single statement must be in braces */<br />

}<br />

while ( new_data_available )<br />

46


process_data (); /* Incorrectly not enclosed in braces */<br />

service_watchdog (); /* Added later but, despite the appearance<br />

(from the indent) it is actually not<br />

part of the body of the while statement,<br />

and is executed only afgter the loop has<br />

terminated */<br />

注 意 , 复 合 语 句 及 其 大 括 号 的 布 局 应 该 根 据 格 式 指 南 来 确 定 。 上 述 只 是 个 例 子 。<br />

规 则 14.9( 强 制 ):<br />

例 如 :<br />

if( 表 达 式 ) 结 构 应 该 跟 随 有 复 合 语 句 。else 关 键 字 应 该 跟 随 有 复 合 语<br />

句 或 者 另 外 的 if 语 句 。<br />

if ( test1 )<br />

{<br />

x = 1 ; /* Even a single statement must be in braces */<br />

}<br />

else if ( test2 )<br />

{<br />

x = 0; /* No need for braces in else if */<br />

}<br />

else<br />

x = 3; /* This was (incorrectly) not enclosed in braces */<br />

y = 2;<br />

/* This line was added later but, despite the appearance<br />

(from the indent) it is actually not part of the else,<br />

and is executed unconditionally */<br />

注 意 , 复 合 语 句 及 其 大 括 号 的 布 局 应 该 根 据 格 式 指 南 来 确 定 。 上 述 只 是 个 例 子 。<br />

规 则 14.10( 强 制 ): 所 有 的 if ... else if 结 构 应 该 由 else 子 句 结 束 。<br />

不 管 何 时 一 条 if 语 句 跟 有 一 个 或 多 个 else if 语 句 都 要 应 用 本 规 则 ; 最 后 的 else if 必 须 跟 有<br />

一 条 else 语 句 。 而 if 语 句 然 后 就 是 else 语 句 的 简 单 情 况 不 在 本 规 则 之 内 。<br />

对 最 后 的 else 语 句 的 要 求 是 保 护 性 编 程 (defensive programming)。else 语 句 或 者 要 执 行 适<br />

当 的 动 作 , 或 者 要 包 含 合 适 的 注 释 以 说 明 为 何 没 有 执 行 动 作 。 这 与 switch 语 句 中 要 求 具 有 最<br />

后 一 个 default 子 句 ( 规 则 15.3) 是 一 致 的 。<br />

例 如 , 下 面 的 代 码 是 简 单 的 if 语 句 :<br />

if ( x > 0)<br />

{<br />

log_error (3) ;<br />

x = 0 ;<br />

} /* else not needed */<br />

而 下 面 的 代 码 描 述 了 if,else if 结 构 :<br />

if ( x < 0 )<br />

{<br />

log_error (3);<br />

47


x = 0;<br />

}<br />

else if (y < 0)<br />

{<br />

x = 3;<br />

}<br />

else /* this else clause is required, even if the */<br />

{ /* programmer expects this will never be reached */<br />

/* no change in value of x */<br />

}<br />

6.15 switch 语 句<br />

C 当 中 switch 语 句 的 语 法 是 软 弱 的 , 允 许 复 杂 的 非 结 构 化 的 行 为 。 下 面 的 文 字 描 述 了<br />

<strong>MISRA</strong>-C 中 定 义 的 switch 语 句 的 标 准 语 法 。 它 们 和 与 之 相 关 的 规 则 强 制 了 简 单 一 致 的 switch<br />

语 句 结 构 。<br />

下 面 的 语 法 规 则 是 对 C 标 准 语 法 规 则 的 补 充 , 所 有 未 在 下 面 定 义 的 语 法 规 则 都 在 C 标 准<br />

中 做 出 了 定 义 。<br />

switch-statement:<br />

switch ( expression ) { case-label-clause-list default-label-clause }<br />

case-label-clause-list:<br />

case-label case-clause opt<br />

case-label-clause-list case-label case-clause opt<br />

case-label:<br />

case constant-expression :<br />

case-clause:<br />

statement-list opt break;<br />

{ declaration-list opt statement-list opt break; }<br />

default-label-clause:<br />

default-label default-clause<br />

default-label:<br />

default :<br />

default-clause:<br />

case-clause<br />

and<br />

statement:<br />

/* labelled_statement removed */<br />

compound_statement<br />

expression_statement<br />

selection_statement<br />

iteration_statement<br />

48


* jump_statement removed or just restricted to return depending on other rules */<br />

规 则 中 还 使 用 了 下 面 的 术 语 :<br />

switch label<br />

case clause<br />

default clause<br />

switch clause<br />

或 者 是 case 标 签 , 或 者 是 default 标 签<br />

任 何 两 个 switch label 之 间 的 代 码<br />

default 标 签 和 switch 语 句 结 尾 之 间 的 代 码<br />

或 者 是 case clause, 或 者 是 default clause<br />

switch 语 句 只 应 包 含 switch label 和 switch clause 而 没 有 其 他 代 码 。<br />

规 则 15.1( 强 制 ):<br />

switch 标 签 只 能 用 在 当 最 紧 密 封 闭 (closely-enclosing) 的 复 合 语 句 是<br />

switch 语 句 体 的 时 候<br />

case 或 default 标 签 的 范 围 应 该 是 做 为 switch 语 句 体 的 复 合 语 句 。 所 有 case 子 句 和 default<br />

子 句 应 该 具 有 相 同 的 范 围 。<br />

规 则 15.2( 强 制 ): 无 条 件 的 break 语 句 应 该 终 止 每 个 非 空 的 switch 子 句 。<br />

[Koenig 22-24]<br />

每 个 switch 子 句 中 的 最 后 一 条 语 句 应 该 是 break 语 句 , 或 者 如 果 switch 子 句 是 复 合 语 句 ,<br />

那 么 复 合 语 句 的 最 后 一 条 语 句 应 该 是 break 语 句 。<br />

规 则 15.3( 强 制 ): switch 语 句 的 最 后 子 句 应 该 是 default 子 句 。<br />

对 最 后 的 default 子 句 的 要 求 是 出 于 保 护 性 编 程 。 该 子 句 应 该 执 行 适 当 的 动 作 , 或 者 包 含<br />

合 适 的 注 释 以 说 明 为 何 没 有 执 行 动 作 。<br />

规 则 15.4( 强 制 ): switch 表 达 式 不 应 是 有 效 的 布 尔 值 。<br />

见 术 语 表 中 的 “Boolean expressions”。<br />

例 如 :<br />

switch ( x == 0) /* not compliant – effectively Boolean */<br />

{<br />

…<br />

规 则 15.5( 强 制 ): 每 个 switch 语 句 至 少 应 有 一 个 case 子 句 。<br />

例 如 :<br />

switch (x)<br />

{<br />

uint8_t var; /* not compliant – decl before 1 st case */<br />

case 0:<br />

a = b;<br />

break; /* break is required here */<br />

case 1: /* empty clause, break not required */<br />

case 2:<br />

a = c; /* executed if x is 1 or 2 */<br />

if ( a == b )<br />

{<br />

case 3: /* not compliant – case is not allowed here */<br />

}<br />

49


6.16 函 数<br />

break;<br />

case 4:<br />

a = b; /* not compliant – non empty drop through */<br />

case 5:<br />

a = c;<br />

break;<br />

default: /* default clause is required */<br />

errorflag = 1; /* should be non-empty if possible */<br />

break;<br />

/* break is required here, in case a<br />

future modification turns this into a<br />

case clause */<br />

}<br />

规 则 16.1( 强 制 ):<br />

函 数 定 义 不 得 带 有 可 变 数 量 的 参 数<br />

[ 未 指 定 15; 未 定 义 25、45、61、70-76]<br />

本 特 性 存 在 许 多 潜 在 的 问 题 。 用 户 不 应 编 写 使 用 可 变 数 量 参 数 的 附 加 函 数 。 这 排 除 了<br />

stdarg.h、va_arg、va_start 和 va_end 的 使 用 。<br />

规 则 16.2( 强 制 ): 函 数 不 能 调 用 自 身 , 不 管 是 直 接 还 是 间 接 的 。<br />

这 意 味 着 在 安 全 相 关 的 系 统 中 不 能 使 用 递 归 函 数 调 用 。 递 归 本 身 承 载 着 可 用 堆 栈 空 间 过<br />

度 的 危 险 , 这 能 导 致 严 重 的 错 误 。 除 非 递 归 经 过 了 非 常 严 格 的 控 制 , 否 则 不 可 能 在 执 行 之 前<br />

确 定 什 么 是 最 坏 情 况 (worst-case) 的 堆 栈 使 用 。<br />

规 则 16.3( 强 制 ):<br />

在 函 数 的 原 型 声 明 中 应 该 为 所 有 参 数 给 出 标 识 符<br />

出 于 兼 容 性 、 清 晰 性 和 可 维 护 性 的 原 因 , 应 该 在 函 数 的 原 型 声 明 中 为 所 有 参 数 给 出 名 字 。<br />

规 则 16.4( 强 制 ):<br />

规 则 16.5( 强 制 ):<br />

函 数 的 声 明 和 定 义 中 使 用 的 标 识 符 应 该 一 致<br />

不 带 参 数 的 函 数 应 当 声 明 为 具 有 void 类 型 的 参 数<br />

[Koenig 59-62]<br />

函 数 应 该 声 明 为 具 有 返 回 类 型 ( 见 规 则 8.2), 如 果 函 数 不 返 回 任 何 数 据 , 返 回 类 型 为 void。<br />

类 似 地 , 如 果 函 数 不 带 参 数 , 参 数 列 表 应 声 明 为 void。 例 如 函 数 myfunc, 如 果 既 不 带 参 数 也<br />

不 返 回 数 据 则 应 声 明 为 :<br />

void myfunc ( void );<br />

规 则 16.6( 强 制 ): 传 递 给 一 个 函 数 的 参 数 应 该 与 声 明 的 参 数 匹 配 。<br />

[ 未 定 义 22]<br />

这 个 问 题 可 以 通 过 使 用 函 数 原 型 完 全 避 免 —— 见 规 则 8.1。 本 规 则 被 保 留 是 因 为 编 译 器 可<br />

能 不 会 标 记 这 样 的 约 束 错 误 。<br />

规 则 16.7( 建 议 ):<br />

函 数 原 型 中 的 指 针 参 数 如 果 不 是 用 于 修 改 所 指 向 的 对 象 , 就 应 该 声 明<br />

为 指 向 const 的 指 针 。<br />

本 规 则 会 产 生 更 精 确 的 函 数 接 口 定 义 。const 限 定 应 当 用 在 所 指 向 的 对 象 而 非 指 针 , 因 为<br />

要 保 护 的 是 对 象 本 身 。<br />

例 如 :<br />

50


void myfunc ( int16_t *param1, const int16_t *param2, int16_t *param3 )<br />

/* param1 : Addresses an object which is modified – no const<br />

param2 : Addresses an object which is not modified – const required<br />

param3 : Addresses an object which is not modified – const missing */<br />

{<br />

*param1 = *param2 + *param3;<br />

return;<br />

}<br />

/* data at address param3 has not been changed, but this is not const therefore<br />

not compliant */<br />

规 则 16.8( 强 制 ):<br />

带 有 non-void 返 回 类 型 的 函 数 其 所 有 退 出 路 径 都 应 具 有 显 式 的 带 表 达<br />

式 的 return 语 句 。<br />

[ 未 定 义 43]<br />

表 达 式 给 出 了 函 数 的 返 回 值 。 如 果 return 语 句 不 带 表 达 式 , 将 导 致 未 定 义 的 行 为 ( 而 且 编<br />

译 器 不 会 给 出 错 误 )。<br />

规 则 16.9( 强 制 ):<br />

use<br />

如 果 程 序 员 写 为 :<br />

函 数 标 识 符 的 使 用 只 能 或 者 加 前 缀 &, 或 者 使 用 括 起 来 的 参 数 列 表 , 列<br />

表 可 以 为 空 。<br />

[Koenig 24]<br />

if (f) /* not compliant – gives a constant non-zero value which is the address of f –<br />

{<br />

}<br />

/* … */<br />

either f () or &f */<br />

那 么 就 不 会 清 楚 其 意 图 是 要 测 试 函 数 的 地 址 是 否 为 NULL, 还 是 执 行 函 数 f () 的 调 用 。<br />

规 则 16.10( 强 制 ): 如 果 函 数 返 回 了 错 误 信 息 , 那 么 错 误 信 息 应 该 进 行 测 试 。<br />

一 个 函 数 ( 标 准 库 中 的 函 数 、 第 三 方 库 函 数 、 或 者 是 用 户 定 义 的 函 数 ) 能 够 提 供 一 些 指<br />

示 错 误 发 生 的 方 法 。 这 可 以 通 过 使 用 错 误 标 记 、 特 殊 的 返 回 数 据 或 者 其 他 手 段 。 不 管 什 么 时<br />

候 函 数 提 供 了 这 样 的 机 制 , 调 用 程 序 应 该 在 函 数 返 回 时 立 刻 检 查 错 误 指 示 。<br />

然 而 要 注 意 到 , 相 对 于 在 函 数 完 成 后 才 检 测 错 误 的 做 法 ( 见 规 则 20.3) 来 说 , 对 函 数 输<br />

入 值 的 检 查 是 更 为 鲁 棒 的 防 止 错 误 的 手 段 。 还 要 注 意 到 , 对 errno 的 使 用 ( 为 了 返 回 函 数 的 错<br />

误 信 息 ) 是 笨 拙 的 并 应 该 谨 慎 使 用 ( 见 规 则 20.5)。<br />

6.17 指 针 和 数 组<br />

规 则 17.1( 强 制 ): 指 针 的 数 学 运 算 只 能 用 在 指 向 数 组 或 数 组 元 素 的 指 针 上 。<br />

[ 未 定 义 30]<br />

对 并 非 指 向 数 组 或 数 组 元 素 的 指 针 做 整 数 加 减 运 算 ( 包 括 增 值 和 减 值 ) 会 导 致 未 定 义 的<br />

行 为 。<br />

规 则 17.2( 强 制 ): 指 针 减 法 只 能 用 在 指 向 同 一 数 组 中 元 素 的 指 针 上 。<br />

51


[ 未 定 义 31]<br />

只 有 当 两 个 指 针 指 向 ( 或 至 少 好 象 是 指 向 了 ) 同 一 数 组 内 的 对 象 时 , 指 针 减 法 才 能 给 出<br />

良 好 定 义 的 结 果 。<br />

规 则 17.3( 强 制 ): >、>=、


struct s {<br />

int8_t * s1; /* compliant */<br />

int8_t * s2; /* compliant */<br />

int8_t * s3; /* compliant */<br />

};<br />

struct s * ps1; /* compliant */<br />

struct s ** ps2; /* compliant */<br />

struct s *** ps3; /* not compliant */<br />

int8_t ** ( *pfunc1 ) (); /* compliant */<br />

int8_t ** ( **pfunc2 ) (); /* compliant */<br />

int8_t ** ( ***pfunc3 ) (); /* not compliant */<br />

int8_t *** ( ** pfunc4 ) (); /* not compliant */<br />

void function ( int8_t * par1,<br />

int8_t ** par2,<br />

int8_t *** par3, /* not compliant */<br />

INTPTR * par4,<br />

INTPTR * const * const par5, /* not compliant */<br />

int8_t * par6[],<br />

int8_t ** par7[] ) /* not compliant */<br />

{<br />

int8_t * ptr1 ;<br />

int8_t ** ptr2 ;<br />

int8_t *** ptr3 ; /* not compliant */<br />

INTPTR * ptr4 ;<br />

INTPTR * const * const ptr5 ; /* not compliant */<br />

int8_t * ptr6[10];<br />

int8_t ** ptr7[10];<br />

}<br />

类 型 解 释 :<br />

• par1 和 ptr1 是 指 向 int8_t 的 指 针 。<br />

• par2 和 ptr2 是 指 向 int8_t 的 指 针 的 指 针 。<br />

• par3 和 ptr3 是 指 向 int8_t 的 指 针 的 指 针 的 指 针 。 这 是 三 级 , 因 此 不 适 合 。<br />

• par4 和 ptr4 扩 展 开 是 指 向 int8_t 的 指 针 的 指 针 。<br />

• par5 和 ptr5 扩 展 开 是 指 向 int8_t 的 指 针 的 const 指 针 的 const 指 针 。 这 是 三 级 , 因 此<br />

不 合 适 。<br />

• par6 是 指 向 int8_t 的 指 针 的 指 针 , 因 为 数 组 被 转 化 成 指 向 数 组 初 始 元 素 的 指 针 。<br />

• ptr6 是 int8_t 类 型 的 指 针 数 组 。<br />

• par7 是 指 向 int8_t 的 指 针 的 指 针 的 指 针 , 因 为 数 组 被 转 化 成 指 向 数 组 初 始 元 素 的 指<br />

针 。 这 是 三 级 , 因 此 不 合 适 。<br />

53


• ptr7 是 指 向 int8_t 的 指 针 的 指 针 数 组 。 这 是 合 适 的 。<br />

规 则 17.6( 强 制 ):<br />

自 动 存 储 对 象 的 地 址 不 应 赋 值 给 其 他 的 在 第 一 个 对 象 已 经 停 止 存 在 后<br />

仍 然 保 持 的 对 象 。<br />

[ 未 定 义 9、26]<br />

如 果 一 个 自 动 对 象 的 地 址 赋 值 给 其 他 的 或 者 具 有 更 大 作 用 域 的 对 象 、 或 者 静 态 对 象 、 或<br />

者 从 一 个 函 数 返 回 的 对 象 , 那 么 在 初 始 对 象 停 止 存 在 ( 其 地 址 成 为 无 效 ) 时 , 包 含 地 址 的 对<br />

象 可 能 会 延 续 存 在 。<br />

例 如 :<br />

int8_t * foobar (void)<br />

{<br />

int8_t local_auto;<br />

return (&local_auto); /* not compliant */<br />

}<br />

6.18 结 构 与 联 合<br />

规 则 18.1( 强 制 ):<br />

所 有 结 构 与 联 合 的 类 型 应 该 在 转 换 单 元 (translation unit) 的 结 尾 是 完<br />

善 的 。<br />

[ 未 定 义 35]<br />

结 构 或 联 合 的 完 整 声 明 应 该 包 含 在 任 何 涉 及 该 结 构 的 转 换 单 元 之 内 。 见 ISO 9899:1990 [2]<br />

中 6.1.2.5 节 关 于 对 不 完 整 类 型 的 详 细 描 述 。<br />

struct tnode * pt; /* tnode is incomplete at this point */<br />

struct tnode<br />

{<br />

int count;<br />

struct tnode * left;<br />

struct tnode * right;<br />

}; /* type tnode is now complete */<br />

规 则 18.2( 强 制 ): 对 象 不 能 赋 值 给 重 叠 (overlapping) 对 象 。<br />

[ 未 定 义 34、35]<br />

当 两 个 对 象 创 建 后 , 如 果 它 们 拥 有 重 叠 的 内 存 空 间 并 把 一 个 拷 贝 给 另 外 一 个 时 , 该 行 为<br />

是 未 定 义 的 。<br />

规 则 18.3( 强 制 ): 不 能 为 了 不 相 关 的 目 的 重 用 一 块 内 存 区 域 。<br />

本 规 则 涉 及 了 使 用 内 存 存 储 某 些 数 据 并 在 程 序 仍 然 运 行 期 间 的 其 他 时 刻 使 用 同 一 块 内 存<br />

存 储 不 相 关 数 据 的 技 术 。 很 明 显 这 依 赖 于 两 段 不 同 的 数 据 块 , 它 们 存 在 于 程 序 运 行 期 间 不 相<br />

连 的 时 间 段 而 且 从 来 不 会 被 同 时 请 求 。<br />

对 于 安 全 相 关 的 系 统 , 不 建 议 这 样 做 , 因 为 它 会 带 来 许 多 危 险 。 比 如 : 一 个 程 序 可 能 试<br />

图 访 问 某 个 区 域 的 某 种 类 型 的 数 据 , 而 当 时 该 区 域 正 在 存 储 其 他 类 型 的 数 据 ( 如 , 由 中 断 引<br />

起 的 )。 这 两 种 类 型 的 数 据 在 存 储 上 可 能 不 同 而 且 可 能 会 侵 占 其 他 数 据 。 这 样 在 每 次 切 换 使 用<br />

时 , 数 据 可 能 不 会 正 确 初 始 化 。 这 样 的 做 法 在 并 发 系 统 中 尤 其 是 危 险 的 。<br />

然 而 要 了 解 有 时 出 于 效 率 的 原 因 可 能 会 要 求 这 样 的 存 储 共 享 。 此 时 就 非 常 需 要 采 取 检 测<br />

手 段 以 确 保 错 误 类 型 的 数 据 永 远 不 会 被 访 问 , 确 保 数 据 始 终 被 适 当 地 初 始 化 了 以 及 确 保 对 其<br />

54


他 部 分 数 据 ( 如 , 由 分 配 不 同 引 起 的 ) 的 访 问 是 不 可 能 的 。 所 采 取 的 检 测 手 段 应 该 归 纳 为 文<br />

档 , 并 在 违 背 本 规 则 的 背 离 内 被 证 明 是 正 确 的 。<br />

可 以 使 用 联 合 或 其 他 手 段 做 到 这 一 点 。<br />

注 意 ,<strong>MISRA</strong>-C 不 想 对 编 译 器 翻 译 源 代 码 的 实 际 行 为 给 出 限 制 , 因 为 用 户 通 常 对 此 没 有<br />

有 效 的 控 制 。 所 以 , 举 例 来 说 , 编 译 器 中 的 内 存 分 配 , 不 管 是 动 态 堆 、 动 态 堆 栈 或 静 态 的 ,<br />

可 能 会 仅 仅 因 为 轻 微 的 代 码 变 化 就 发 生 显 著 的 改 变 , 即 使 是 在 相 同 的 优 化 级 别 上 。 还 要 注 意<br />

的 是 , 某 些 优 化 会 合 理 地 产 生 , 甚 至 在 用 户 没 有 做 出 这 样 的 请 求 时 。<br />

规 则 18.4( 强 制 ): 不 要 使 用 联 合 。<br />

[ 实 现 27]<br />

规 则 18.3 禁 止 为 不 相 关 的 目 的 重 用 内 存 区 域 , 然 而 , 即 使 内 存 区 域 是 为 了 相 关 目 的 重 用<br />

的 , 仍 然 会 存 在 数 据 被 误 解 的 风 险 。 因 此 , 提 出 本 规 则 禁 止 针 对 任 何 目 的 而 使 用 联 合 。<br />

尽 管 如 此 , 要 认 识 到 在 某 些 情 况 下 需 要 谨 慎 地 使 用 联 合 以 构 建 有 效 率 的 实 现 。 发 生 这 些<br />

情 况 时 , 如 果 所 有 相 关 的 定 义 实 现 的 行 为 被 归 纳 为 文 档 了 , 那 么 对 本 规 则 的 违 背 也 是 可 以 接<br />

受 的 。 实 践 中 , 可 以 在 设 计 文 档 内 指 出 编 译 器 手 册 的 实 现 章 节 。 与 此 有 关 的 实 现 行 为 的 种 类<br />

是 :<br />

• 填 充 —— 在 联 合 的 结 尾 插 入 了 多 少 填 充<br />

• 排 列 —— 在 联 合 中 排 列 了 多 少 结 构 成 员<br />

• 存 储 次 序 (endianess)—— 数 据 字 中 最 有 效 的 字 节 是 存 储 在 最 低 内 存 地 址 还 是 最 高 地<br />

址<br />

• 位 次 序 (bit-order)—— 字 节 中 的 位 是 如 何 计 数 的 以 及 如 何 分 配 在 位 域 中 的<br />

对 如 下 情 况 违 背 规 则 是 可 以 接 受 的 :(a) 数 据 的 打 包 和 解 包 , 如 在 发 送 和 接 收 消 息 时 ;(b)<br />

实 现 变 量 录 取 (variant records), 假 设 变 量 是 由 通 用 的 域 (common fields) 区 分 的 。 不 带 区 分<br />

器 (differentiator) 的 变 量 录 取 在 任 何 情 况 下 都 是 不 合 适 的 。<br />

数 据 打 包 和 解 包<br />

在 本 例 中 , 使 用 联 合 访 问 一 个 32 位 数 据 字 的 字 节 以 存 储 从 高 字 节 优 先 的 网 络 上 接 收 到 的<br />

字 节 。 这 种 特 殊 假 设 :<br />

• uint32_t 类 型 占 据 32 位<br />

• uint8_t 类 型 占 据 8 位<br />

• 实 现 把 数 据 字 的 最 高 有 效 字 节 存 储 在 最 低 的 内 存 地 址<br />

实 现 接 收 和 打 包 的 代 码 如 下 :<br />

typedef union {<br />

uint32_t word;<br />

uint8_t bytes[4];<br />

} word_msg_t;<br />

uint32_t read_word_big_endian (void)<br />

{<br />

word_msg_t tmp;<br />

tmp.bytes[0] = read_byte ();<br />

tmp.bytes[1] = read_byte ();<br />

tmp.bytes[2] = read_byte ();<br />

tmp.bytes[3] = read_byte ();<br />

55


}<br />

return (tmp.word);<br />

值 得 注 意 的 是 上 面 的 函 数 体 可 以 写 成 如 下 可 移 植 的 形 式 :<br />

uint32_t read_word_big_endian (void)<br />

{<br />

uint32_t word;<br />

word = ( ( uint32_t ) read_byte () )


uint16_t station_to_disconnect;<br />

} ccp_disconnect_t;<br />

/* The variant */<br />

typedef union {<br />

ccp_common_t common;<br />

ccp_connect_t connect;<br />

ccp_disconnect_t disconnect;<br />

} ccp_message_t;<br />

void process_ccp_message (ccp_message_t *msg)<br />

{<br />

switch (msg->common.msg_type)<br />

{<br />

case Ccp_connect:<br />

if (MY_STATION == msg->connect.station_to_connect)<br />

{<br />

ccp_connect ();<br />

}<br />

break;<br />

case Ccp_disconnect:<br />

if (MY_STATION == msg->disconnect.station_to_disconnect)<br />

{<br />

if (PERM_DISCONNECT == msg->disconnect.disconnect_command)<br />

{<br />

ccp_disconnect ();<br />

}<br />

}<br />

break;<br />

default:<br />

break; /* ignore unknown commands */<br />

}<br />

}<br />

6.19 预 处 理 指 令<br />

规 则 19.1( 建 议 ): 文 件 中 的 #include 语 句 之 前 只 能 是 其 他 预 处 理 指 令 或 注 释 。<br />

代 码 文 件 中 所 有 #include 指 令 应 该 成 组 放 置 在 接 近 文 件 顶 部 的 位 置 。 本 规 则 说 明 , 文 件 中<br />

可 以 优 先 #include 语 句 放 置 的 只 能 是 其 他 预 处 理 指 令 或 注 释 。<br />

规 则 19.2( 建 议 ): #include 指 令 中 的 头 文 件 名 字 里 不 能 出 现 非 标 准 字 符 。<br />

[ 未 定 义 14]<br />

如 果 在 头 文 件 名 字 预 处 理 标 记 的 < 和 > 限 定 符 或 ” 和 ” 限 定 符 之 间 使 用 了 ‘ ,\ ,<br />

57


或 /* 字 符 , 该 行 为 是 未 定 义 的 。<br />

规 则 19.3( 强 制 ): #include 预 处 理 指 令 应 该 跟 随 或 ”filename” 序 列 。<br />

例 如 , 如 下 语 句 是 允 许 的 :<br />

#include “ filename.h”<br />

#include <br />

#define FILE “filename.h”<br />

#include FILE<br />

规 则 19.4( 强 制 ):<br />

[ 未 定 义 48]<br />

C 的 宏 只 能 扩 展 为 用 大 括 号 括 起 来 的 初 始 化 、 常 量 、 小 括 号 括 起 来 的<br />

表 达 式 、 类 型 限 定 符 、 存 储 类 标 识 符 或 do-while-zero 结 构 。<br />

[Koenig 82-84]<br />

这 些 是 宏 当 中 所 有 可 允 许 使 用 的 形 式 。 存 储 类 标 识 符 和 类 型 限 定 符 包 括 诸 如 extern、static<br />

和 const 这 样 的 关 键 字 。 使 用 任 何 其 他 形 式 的 #define 都 可 能 导 致 非 预 期 的 行 为 , 或 者 是 非 常 难<br />

懂 的 代 码 。<br />

特 别 的 , 宏 不 能 用 于 定 义 语 句 或 部 分 语 句 , 除 了 do-while 结 构 。 宏 也 不 能 重 定 义 语 言 的<br />

语 法 。 宏 的 替 换 列 表 中 的 所 有 括 号 , 不 管 哪 种 形 式 的 ()、{}、[] 都 应 该 成 对 出 现 。<br />

do-while-zero 结 构 ( 见 下 面 的 例 子 ) 是 在 宏 语 句 体 中 唯 一 可 接 受 的 具 有 完 整 语 句 的 形 式 。<br />

do-while-zero 结 构 用 于 封 装 语 句 序 列 并 确 保 其 是 正 确 的 。 注 意 : 在 宏 语 句 体 的 末 尾 必 须 省 略 分<br />

号 。<br />

例 如 :<br />

/* The following are compliant */<br />

#define PI 3.14159F /* Constant */<br />

#define XSTAL 10000000 /* Constant */<br />

#define CLOCK (XSTAL / 16) /* Constant expression */<br />

#define PLUS2(X) ( (X) + 2 ) /* Macro expanding to expression */<br />

#define STOR extern /* storage class specifier */<br />

#define INIT(value) { (value), 0, 0 } /* braced initialiser */<br />

#define READ_TIME_32 () \<br />

do { \<br />

DISABLE_INTERRUPTS (); \<br />

time_now = (uint32_t) TIMER_HI


通 常 不 一 定 需 要 ( 见 规 则 19.6)。<br />

规 则 19.6( 强 制 ):<br />

不 要 使 用 #undef。<br />

通 常 ,#undef 是 不 需 要 的 。 当 它 出 现 在 代 码 中 时 , 能 使 宏 的 存 在 或 含 义 产 生 混 乱 。<br />

规 则 19.7( 建 议 ):<br />

函 数 的 使 用 优 先 选 择 函 数 宏 (function-like macro)。<br />

[Koenig 78-81]<br />

由 于 宏 能 提 供 比 函 数 优 越 的 速 度 , 函 数 提 供 了 一 种 更 为 安 全 和 鲁 棒 的 机 制 。 在 进 行 参 数<br />

的 类 型 检 查 时 尤 其 如 此 。 函 数 宏 的 问 题 在 于 它 可 能 会 多 次 计 算 参 数 。<br />

规 则 19.8( 强 制 ):<br />

函 数 宏 的 调 用 不 能 缺 少 参 数<br />

[ 未 定 义 49]<br />

这 是 一 个 约 束 错 误 , 但 是 预 处 理 器 知 道 并 忽 略 此 问 题 。 函 数 宏 中 的 每 个 参 数 的 组 成 必 须<br />

至 少 有 一 个 预 处 理 标 记 , 否 则 其 行 为 是 未 定 义 的 。<br />

规 则 19.9( 强 制 ): 传 递 给 函 数 宏 的 参 数 不 能 包 含 看 似 预 处 理 指 令 的 标 记 。<br />

[ 未 定 义 50]<br />

如 果 任 何 参 数 的 行 为 类 似 预 处 理 指 令 , 使 用 宏 替 代 函 数 时 的 行 为 将 是 不 可 预 期 的 。<br />

规 则 19.10( 强 制 ): 在 定 义 函 数 宏 时 , 每 个 参 数 实 例 都 应 该 以 小 括 号 括 起 来 , 除 非 它 们 做<br />

为 # 或 ## 的 操 作 数 。<br />

函 数 宏 的 定 义 中 , 参 数 应 该 用 小 括 号 括 起 来 。 例 如 一 个 abs 函 数 可 以 定 义 成 :<br />

#define abs (x) ( ( (x) >= 0 ) ? (x) : -(x) )<br />

不 能 定 义 成 :<br />

#define abs (x) ( ( (x) >= 0 ) ? x : -x )<br />

[Koenig 78-81]<br />

如 果 不 坚 持 本 规 则 , 那 么 当 预 处 理 器 替 代 宏 进 入 代 码 时 , 操 作 符 优 先 顺 序 将 不 会 给 出 要<br />

求 的 结 果 。<br />

考 虑 前 面 第 二 个 不 正 确 的 定 义 被 替 代 时 会 发 生 什 么 :<br />

z = abs ( a – b );<br />

将 给 出 如 下 结 果 :<br />

z = ( ( a – b >= 0 ) ? a – b : -a – b );<br />

子 表 达 式 – a - b 相 当 于 (-a)-b, 而 不 是 希 望 的 –(a-b)。 把 所 有 参 数 都 括 进 小 括 号 中 就 可<br />

以 避 免 这 样 的 问 题 。<br />

规 则 19.11( 强 制 ):<br />

预 处 理 指 令 中 所 有 宏 标 识 符 在 使 用 前 都 应 先 定 义 , 除 了 #ifdef 和 #ifndef<br />

指 令 及 defined() 操 作 符 。<br />

如 果 试 图 在 预 处 理 指 令 中 使 用 未 经 定 义 的 标 识 符 , 预 处 理 器 有 时 不 会 给 出 任 何 警 告 但 会<br />

假 定 其 值 为 零 。#ifdef、#ifndef 和 defined() 用 来 测 试 宏 是 否 存 在 并 由 此 进 行 排 除 。<br />

例 如 :<br />

#if x < 0 /* x assumed to be zero if not defined */<br />

在 标 识 符 被 使 用 之 前 要 考 虑 使 用 #ifdef 进 行 测 试 。<br />

注 意 , 预 处 理 标 识 符 可 以 使 用 #define 指 令 来 定 义 也 可 以 在 编 译 器 调 用 所 指 定 的 选 项 中 定<br />

义 。 然 而 更 多 的 是 使 用 #define 指 令 。<br />

规 则 19.12( 强 制 ): 在 单 一 的 宏 定 义 中 最 多 可 以 出 现 一 次 # 或 ## 预 处 理 器 操 作 符 。<br />

[ 未 指 定 12]<br />

59


与 # 或 ## 预 处 理 器 操 作 符 相 关 的 计 算 次 序 如 果 未 被 指 定 则 会 产 生 问 题 。 为 避 免 该 问<br />

题 , 在 单 一 的 宏 定 义 中 只 能 使 用 其 中 一 种 操 作 符 ( 即 , 一 个 #、 或 一 个 ##、 或 都 不 用 )。<br />

规 则 19.13( 建 议 ): 不 要 使 用 # 或 ## 预 处 理 器 操 作 符 。<br />

[ 未 指 定 12]<br />

与 # 或 ## 预 处 理 器 操 作 符 相 关 的 计 算 次 序 如 果 未 被 指 定 则 会 产 生 问 题 。 编 译 器 对 这 些<br />

操 作 符 的 实 现 是 不 一 致 的 。 为 避 免 这 些 问 题 , 最 好 不 要 使 用 它 们 。<br />

规 则 19.14( 强 制 ): defined 预 处 理 操 作 符 只 能 使 用 两 种 标 准 形 式 之 一 。<br />

defined 预 处 理 操 作 符 的 两 种 可 允 许 的 形 式 为 :<br />

defined (identifier)<br />

defined identifier<br />

任 何 其 他 的 形 式 都 会 导 致 未 定 义 的 行 为 , 比 如 :<br />

#if defined (X > Y) /* not compliant – undefined behaviour */<br />

[ 未 定 义 47]<br />

在 #if 或 #elif 预 处 理 指 令 的 扩 展 中 定 义 的 标 记 也 会 导 致 未 定 义 的 行 为 , 应 该 避 免 。 如 :<br />

#define DEFINED defined<br />

#if DEFINED (X) /* not compliant – undefined behaviour */<br />

规 则 19.15( 强 制 ): 应 该 采 取 防 范 措 施 以 避 免 一 个 头 文 件 的 内 容 被 包 含 两 次 。<br />

当 转 换 单 元 (translation unit) 包 含 了 复 杂 层 次 的 嵌 套 头 文 件 时 , 会 发 生 某 头 文 件 被 包 含<br />

多 于 一 次 的 情 形 。 这 最 多 会 导 致 混 乱 。 如 果 它 导 致 了 多 个 定 义 或 定 义 冲 突 , 其 结 果 将 是 未 定<br />

义 的 或 者 是 错 误 的 行 为 。<br />

多 次 包 含 一 个 头 文 件 可 以 通 过 认 真 的 设 计 来 避 免 。 如 果 不 能 做 到 这 一 点 , 就 需 要 采 取 阻<br />

止 头 文 件 内 容 被 包 含 多 于 一 次 的 机 制 。 通 常 的 手 段 是 为 每 个 文 件 配 置 一 个 宏 ; 当 头 文 件 第 一<br />

次 被 包 含 时 就 定 义 这 个 宏 , 并 在 头 文 件 被 再 次 包 含 时 使 用 它 以 排 除 文 件 内 容 。<br />

例 如 , 一 个 名 为 “ahdr.h” 的 文 件 可 以 组 织 如 下 :<br />

#ifndef AHDR_H<br />

#define AHDR_H<br />

/* The following lines will be excluded by the preprocessor if the file is included<br />

more than once */<br />

…<br />

#endif<br />

或 者 可 以 使 用 下 面 的 形 式<br />

#ifdef AHDR_H<br />

#error Header file is already included<br />

#else<br />

#define AHDR_H<br />

/* The following lines will be excluded by the preprocessor if the file is included<br />

more than once */<br />

…<br />

#endif<br />

规 则 19.16( 强 制 ): 预 处 理 指 令 在 句 法 上 应 该 是 有 意 义 的 , 即 使 是 在 被 预 处 理 器 排 除 的 情<br />

60


况 下 。<br />

当 一 段 源 代 码 被 预 处 理 指 令 排 除 时 , 每 个 被 排 除 语 句 的 内 容 被 忽 略 直 到 出 现 一 个 #else、<br />

#elif 或 #endif 指 令 ( 根 据 上 下 文 内 容 )。 如 果 其 中 一 个 被 排 除 指 令 的 组 成 形 式 不 好 (badly<br />

formed), 编 译 器 忽 略 它 时 不 会 给 出 任 何 警 告 , 这 将 带 来 不 幸 的 后 果 。<br />

本 规 则 要 求 所 有 预 处 理 指 令 在 句 法 上 是 有 效 的 , 即 使 它 们 出 现 在 被 排 除 的 代 码 块 中 。<br />

特 别 地 , 要 确 保 #else 和 #endif 指 令 后 不 要 跟 随 除 空 格 之 外 的 任 何 字 符 。 在 强 制 执 行 这<br />

个 ISO 要 求 时 编 译 器 并 非 始 终 一 致 。<br />

#define AAA 2<br />

...<br />

int foo (void)<br />

{<br />

int x = 0 ;<br />

...<br />

#ifndef AAA<br />

x = 1 ;<br />

#else1 /* Not compliant */<br />

x = AAA ;<br />

#endif<br />

...<br />

retun x ;<br />

}<br />

规 则 19.17( 强 制 ): 所 有 的 #else、#elif 和 #endif 预 处 理 指 令 应 该 同 与 它 们 相 关 的 #if 或<br />

#ifdef 指 令 放 在 相 同 的 文 件 中 。<br />

当 语 句 块 的 包 含 和 排 除 是 被 一 系 列 预 处 理 指 令 控 制 时 , 如 果 所 有 相 关 联 的 指 令 没 有 出 现<br />

在 同 一 个 文 件 中 就 会 产 生 混 乱 。 本 规 则 要 求 所 有 的 预 处 理 指 令 序 列 #if / #ifdef ... #elif ... #else ...<br />

#endif 应 该 放 在 同 一 个 文 件 中 。 遵 循 本 规 则 会 保 持 良 好 的 代 码 结 构 并 能 避 免 维 护 性 问 题 。<br />

注 意 , 这 并 不 排 除 把 所 有 这 样 的 指 令 放 在 众 多 被 包 含 文 件 中 的 可 能 性 , 只 要 与 某 一 序 列<br />

相 关 的 所 有 指 令 放 在 一 个 文 件 中 即 可 。<br />

file.c<br />

#define A<br />

...<br />

#ifdef A<br />

...<br />

#include “ file1.h”<br />

#<br />

#endif<br />

...<br />

#if 1<br />

#include “ file2.h”<br />

...<br />

EOF<br />

61


file1.h<br />

#if 1<br />

...<br />

#endif /* Compliant */<br />

EOF<br />

file2.h<br />

...<br />

#endif /* Not compliant */<br />

6.20 标 准 库<br />

规 则 20.1( 强 制 ): 标 准 库 中 保 留 的 标 识 符 、 宏 和 函 数 不 能 被 定 义 、 重 定 义 或 取 消 定 义 。<br />

[ 未 定 义 54、57、58、62]<br />

通 常 #undef 一 个 定 义 在 标 准 库 中 的 宏 是 件 坏 事 。 同 样 不 好 的 是 ,#define 一 个 宏 名 字 ,<br />

而 该 名 字 是 C 的 保 留 标 识 符 或 者 标 准 库 中 做 为 宏 、 对 象 或 函 数 名 字 的 C 关 键 字 。 例 如 , 存 在<br />

一 些 特 殊 的 保 留 字 和 函 数 名 字 , 它 们 的 作 用 为 人 所 熟 知 , 如 果 对 它 们 重 新 定 义 或 取 消 定 义 就<br />

会 产 生 一 些 未 定 义 的 行 为 。 这 些 名 字 包 括 defined、__LINE__、__FILE__、__DATE__、<br />

__TIME__、__STDC__、errno 和 assert。<br />

#undef 的 使 用 也 可 以 参 见 规 则 19.6。<br />

ISO C 的 保 留 标 识 符 在 本 文 档 中 参 见 7.1.3 节 和 7.13 节 关 于 ISO 9899 :1990 [2], 同 时 也 应<br />

该 被 编 译 器 的 编 写 者 写 入 文 档 。 通 常 , 所 有 以 下 划 线 开 始 的 标 识 符 都 是 保 留 的 。<br />

规 则 20.2( 强 制 ): 不 能 重 用 标 准 库 中 宏 、 对 象 和 函 数 的 名 字 。<br />

如 果 程 序 员 使 用 了 标 准 库 中 宏 、 对 象 或 函 数 的 新 版 本 ( 如 , 功 能 增 强 或 输 入 值 检 查 ), 那<br />

么 更 改 过 的 宏 、 对 象 或 函 数 应 该 具 有 新 的 名 字 。 这 是 用 来 避 免 不 知 是 使 用 了 标 准 的 宏 、 对 象<br />

或 函 数 还 是 使 用 了 它 们 的 更 新 版 本 所 带 来 的 任 何 混 淆 。 所 以 , 举 例 来 说 , 如 果 sqrt 函 数 的 新<br />

版 本 被 写 做 检 查 输 入 值 非 负 , 那 么 这 新 版 本 不 能 命 名 为 “sqrt” 而 应 该 给 出 新 的 名 字 。<br />

规 则 20.3( 强 制 ): 传 递 给 库 函 数 的 值 必 须 检 查 其 有 效 性 。<br />

[ 未 定 义 60、63; 实 现 45、47]<br />

C 标 准 库 中 的 许 多 函 数 根 据 ISO 标 准 [2] 并 不 需 要 检 查 传 递 给 它 们 的 参 数 的 有 效 性 。 即<br />

使 标 准 要 求 这 样 , 或 者 编 译 器 的 编 写 者 声 明 要 这 么 做 , 也 不 能 保 证 会 做 出 充 分 的 检 查 。 因 此 ,<br />

程 序 员 应 该 为 所 有 带 有 严 格 输 入 域 的 库 函 数 ( 标 准 库 、 第 三 方 库 及 自 己 定 义 的 库 ) 提 供 适 当<br />

的 输 入 值 检 查 机 制 。<br />

具 有 严 格 输 入 域 并 需 要 检 查 的 函 数 例 子 为 :<br />

• math.h 中 的 许 多 数 学 函 数 , 比 如 :<br />

负 数 不 能 传 递 给 sqrt 或 log 函 数 ;<br />

fmod 函 数 的 第 二 个 参 数 不 能 为 零<br />

• toupper 和 tolower: 当 传 递 给 toupper 函 数 的 参 数 不 是 小 写 字 符 时 , 某 些 实 现 能 产 生<br />

并 非 预 期 的 结 果 (tolower 函 数 情 况 类 似 )<br />

• 如 果 为 ctype.h 中 的 字 符 测 试 函 数 传 递 无 效 的 值 时 会 给 出 未 定 义 的 行 为<br />

• 应 用 于 大 多 数 负 整 数 的 abs 函 数 给 出 未 定 义 的 行 为<br />

在 math.h 中 , 尽 管 大 多 数 数 学 库 函 数 定 义 了 它 们 允 许 的 输 入 域 , 但 在 域 发 生 错 误 时 它 们<br />

的 返 回 值 仍 可 能 随 编 译 器 的 不 同 而 不 同 。 因 此 , 对 这 些 函 数 来 说 , 预 先 检 查 其 输 入 值 的 有 效<br />

62


性 就 变 得 至 关 重 要 。<br />

程 序 员 在 使 用 函 数 时 , 应 该 识 别 应 用 于 这 些 函 数 之 上 的 任 何 的 域 限 制 ( 这 些 限 制 可 能 会<br />

也 可 能 不 会 在 文 档 中 说 明 ), 并 且 要 提 供 适 当 的 检 查 以 确 认 这 些 输 入 值 位 于 各 自 域 中 。 当 然 ,<br />

在 需 要 时 , 这 些 值 还 可 以 更 进 一 步 加 以 限 制 。<br />

有 许 多 方 法 可 以 满 足 本 规 则 的 要 求 , 包 括 :<br />

• 调 用 函 数 前 检 查 输 入 值<br />

• 设 计 深 入 函 数 内 部 的 检 查 手 段 。 这 种 方 法 尤 其 适 应 于 实 验 室 内 开 发 的 库 , 纵 然 它 也<br />

可 以 用 于 买 进 的 第 三 方 库 ( 如 果 第 三 方 库 的 供 应 商 声 明 他 们 已 内 置 了 检 查 的 话 )。<br />

• 产 生 函 数 的 “ 封 装 ”(wrapped) 版 本 , 在 该 版 本 中 首 先 检 查 输 入 , 然 后 调 用 原 始 的 函<br />

数 。<br />

• 静 态 地 声 明 输 入 参 数 永 远 不 会 采 取 无 效 的 值 。<br />

注 意 , 在 检 查 函 数 的 浮 点 参 数 时 ( 浮 点 参 数 在 零 点 上 为 奇 点 ), 适 当 的 做 法 是 执 行 其 是 否<br />

为 零 的 检 查 。 这 对 规 则 13.3 而 言 是 可 以 接 受 的 例 外 , 不 需 给 出 背 离 。 然 而 如 果 当 参 数 趋 近 于<br />

零 时 , 函 数 值 的 量 级 趋 近 无 穷 的 话 , 仍 然 有 必 要 检 查 其 在 零 点 ( 或 其 他 任 何 奇 点 ) 上 的 容 限 ,<br />

这 样 可 以 避 免 溢 出 的 发 生 。<br />

规 则 20.4( 强 制 ):<br />

不 能 使 用 动 态 堆 的 内 存 分 配<br />

这 排 除 了 对 函 数 alloc、malloc、realloc 和 free 的 使 用 。<br />

[ 未 指 定 19; 未 定 义 91、92; 实 现 69;Koenig 32]<br />

涉 及 动 态 内 存 分 配 时 , 存 在 整 个 范 围 内 的 未 指 定 的 、 未 定 义 的 和 实 现 定 义 的 行 为 , 以 及<br />

其 他 大 量 的 潜 在 缺 陷 。 动 态 堆 内 存 分 配 能 够 导 致 内 存 泄 漏 、 数 据 不 一 致 、 内 存 耗 尽 和 不 确 定<br />

的 行 为 。<br />

注 意 , 某 些 实 现 可 能 会 使 用 动 态 堆 内 存 的 分 配 以 实 现 其 他 函 数 ( 如 库 string.h 中 的 函 数 )。<br />

如 果 这 种 情 况 发 生 , 也 需 要 避 免 使 用 这 些 函 数 。<br />

规 则 20.5( 强 制 ):<br />

不 要 使 用 错 误 指 示 errno。<br />

[ 实 现 46;Koenig 73]<br />

errno 做 为 C 的 简 捷 工 具 , 在 理 论 上 是 有 用 的 , 但 在 实 际 中 标 准 没 有 很 好 地 定 义 它 。 一 个<br />

非 零 值 可 以 指 示 问 题 的 发 生 , 也 可 以 不 用 它 指 示 ; 做 为 结 果 不 应 该 使 用 它 。 即 使 对 于 那 些 已<br />

经 良 好 定 义 了 errno 的 函 数 而 言 , 宁 可 在 调 用 函 数 前 检 查 输 入 值 也 不 依 靠 errno 来 捕 获 错 误 ( 见<br />

规 则 16.10)。<br />

规 则 20.6( 强 制 ):<br />

不 应 使 用 库 中 的 宏 offsetof。<br />

[ 未 定 义 59]<br />

当 这 个 宏 的 操 作 数 的 类 型 不 兼 容 或 使 用 了 位 域 时 , 它 的 使 用 会 导 致 未 定 义 的 行 为 。<br />

规 则 20.7( 强 制 ):<br />

不 应 使 用 setjmp 宏 和 longjmp 函 数<br />

setjmp 和 longjmp 允 许 绕 过 正 常 的 函 数 调 用 机 制 , 不 应 该 使 用 。<br />

规 则 20.8( 强 制 ):<br />

不 应 使 用 信 号 处 理 工 具 <br />

信 号 处 理 包 含 了 实 现 定 义 的 和 未 定 义 的 行 为 。<br />

规 则 20.9( 强 制 ):<br />

在 产 品 代 码 中 不 应 使 用 输 入 / 输 出 库 。<br />

[ 未 指 定 14; 未 定 义 64-67;Koenig 74]<br />

[ 未 定 义 68、69; 实 现 48-52;Koenig 74]<br />

[ 未 指 定 2-5,16-18; 未 定 义 77-89; 实 现 53-68]<br />

这 包 含 文 件 和 I/O 函 数 fgetpos、fopen、ftell、gets、perror、remove、rename 和 ungetc。<br />

63


流 和 文 件 I/O 具 有 大 量 未 指 定 的 、 未 定 义 的 和 实 现 定 义 的 行 为 。 本 文 档 中 假 定 正 常 情 况 下<br />

嵌 入 式 系 统 的 产 品 代 码 中 不 需 要 它 们 。<br />

如 果 产 品 代 码 中 需 要 stdio.h 中 的 任 意 特 性 , 那 么 需 要 了 解 与 此 特 性 相 关 的 某 些 问 题 。<br />

规 则 20.10( 强 制 ): 不 应 使 用 库 中 的 函 数 atof、atoi 和 atol。<br />

当 字 符 串 不 能 被 转 换 时 , 这 些 函 数 具 有 未 定 义 的 行 为 。<br />

规 则 20.11( 强 制 ):<br />

不 应 使 用 库 中 的 函 数 abort、exit、getenv 和 system。<br />

[ 未 定 义 90]<br />

[ 未 定 义 93; 实 现 70-73]<br />

正 常 情 况 下 , 嵌 入 式 系 统 不 需 要 这 些 函 数 , 因 为 嵌 入 式 系 统 一 般 不 需 要 同 环 境 进 行 通 讯 。<br />

如 果 一 个 应 用 中 必 需 这 些 函 数 , 那 么 一 定 要 在 所 处 环 境 中 检 查 这 些 函 数 的 实 现 定 义 的 行 为 。<br />

规 则 20.12( 强 制 ): 不 应 使 用 库 中 的 时 间 处 理 函 数 。<br />

[ 未 指 定 22; 未 定 义 97; 实 现 75、76]<br />

包 括 time、strftime。 这 个 库 同 时 钟 有 关 。 许 多 方 面 都 是 实 现 定 义 的 或 未 指 定 的 , 如 时 间<br />

的 格 式 。 如 果 要 使 用 time.h 中 的 任 一 功 能 , 那 么 必 须 要 确 定 所 用 编 译 器 对 它 的 准 确 实 现 , 并<br />

给 出 背 离 。<br />

6.21 运 行 时 错 误<br />

规 则 21.1( 强 制 ): 最 大 限 度 降 低 运 行 时 错 误 必 须 要 确 保 至 少 使 用 了 下 列 方 法 之 一 :<br />

a) 静 态 分 析 工 具 / 技 术 ;<br />

b) 动 态 分 析 工 具 / 技 术 ;<br />

c) 显 式 的 代 码 检 测 以 处 理 运 行 时 故 障<br />

[ 未 定 义 19、26、94]<br />

运 行 时 检 测 是 个 问 题 , 它 不 专 属 于 C, 但 C 程 序 员 需 要 加 以 特 别 的 注 意 。 这 是 因 为 C 语<br />

言 在 提 供 任 何 运 行 时 检 测 方 面 能 力 较 弱 。 对 于 鲁 棒 的 软 件 来 说 , 动 态 检 测 是 必 需 的 , 但 C 的<br />

实 现 不 需 要 。 因 此 C 程 序 员 需 要 谨 慎 考 虑 的 问 题 是 , 在 任 何 可 能 出 现 运 行 时 错 误 的 地 方 增 加<br />

代 码 的 动 态 检 测 。<br />

当 表 达 式 仅 仅 由 处 在 良 好 定 义 范 围 内 的 值 组 成 时 , 倘 若 可 以 声 称 , 对 于 所 有 处 在 定 义 范<br />

围 内 的 值 来 说 不 会 发 生 异 常 的 话 , 运 行 时 检 测 就 不 是 必 需 的 。 如 果 使 用 了 这 样 的 声 明 , 它 应<br />

该 与 它 所 依 赖 的 假 设 一 起 组 织 成 文 档 。 然 而 如 果 使 用 了 这 种 方 法 , 一 定 要 小 心 的 是 , 后 续 的<br />

代 码 改 变 可 能 会 使 原 先 的 假 设 无 效 , 或 者 要 小 心 出 于 某 种 原 因 而 改 变 了 原 先 的 假 设 。<br />

下 面 的 条 款 给 出 了 在 何 处 需 要 考 虑 提 供 动 态 检 测 的 指 导 :<br />

• 数 学 运 算 错 误<br />

它 包 括 表 达 式 运 算 错 误 , 如 溢 出 、 下 溢 出 、 零 除 或 移 位 时 有 效 位 的 丢 失 。<br />

考 虑 整 数 溢 出 , 注 意 , 无 符 号 的 整 数 计 算 不 会 产 生 严 格 意 义 上 的 溢 出 ( 产 生 未 定 义<br />

的 值 ), 但 是 会 产 生 值 的 折 叠 (wrap-around)( 产 生 经 过 定 义 的 但 可 能 是 错 误 的 值 )。<br />

• 指 针 运 算<br />

确 保 在 动 态 计 算 一 个 地 址 时 , 被 计 算 的 地 址 是 合 理 的 并 指 向 某 个 有 意 义 的 地 方 。 特<br />

别 要 保 证 指 向 一 个 结 构 或 数 组 的 内 部 , 那 么 当 指 针 增 加 或 者 改 变 后 仍 然 指 向 同 一 个<br />

结 构 或 数 组 。 参 见 指 针 运 算 的 限 制 —— 规 则 17.1、17.2、17.4。<br />

• 数 组 界 限 错 误<br />

64


在 使 用 数 组 索 引 元 素 前 要 确 保 它 处 于 数 组 大 小 的 界 限 之 内<br />

• 函 数 参 数<br />

见 规 则 20.3<br />

• 引 用 指 针 的 值 (pointer dereferencing)<br />

如 果 一 个 函 数 返 回 一 个 指 针 , 而 接 下 来 该 指 针 的 值 被 引 用 , 那 么 程 序 首 先 要 检 查 指<br />

针 不 是 NULL。 在 一 个 函 数 内 部 , 指 出 哪 个 指 针 可 以 保 持 NULL 哪 个 指 针 不 可 以 保<br />

持 NULL 是 相 对 简 单 的 事 情 。 而 跨 越 函 数 界 限 , 尤 其 是 在 调 用 定 义 在 其 他 文 件 或 库<br />

中 的 函 数 时 , 这 就 困 难 得 多 。<br />

/* Given a pointer to a message, check the message header and return<br />

* a pointer to the body of the message or NULL if the message is<br />

* invalid */<br />

const char_t *msg_body (const char_t *msg)<br />

{<br />

const char_t *body = NULL;<br />

if (msg != NULL)<br />

{<br />

if (msg_header_valid (msg) )<br />

{<br />

body = &msg[MSG_HEADER_SIZE];<br />

}<br />

}<br />

return (body);<br />

}<br />

…<br />

char_t msg_buffer[MAX_MSG_SIZE];<br />

const char_t *payload;<br />

…<br />

payload = msg_body (msg_buffer);<br />

if (payload != NULL)<br />

{<br />

/* process the message payload */<br />

}<br />

用 于 最 小 化 运 行 时 错 误 的 技 术 应 该 详 细 计 划 并 写 成 文 档 , 比 如 , 在 设 计 标 准 、 测 试 计 划 、<br />

静 态 分 析 配 置 文 件 、 代 码 检 查 清 单 中 。<br />

65


7 References<br />

[1] <strong>MISRA</strong> Guidelines for the Use of the C Language In Vehicle Based Software, ISBN<br />

0-9524156-9-0. Motor Industry Research Association. Nuneaton. April 1998<br />

[2] ISO/IEC 9899:1990. Programming languages - C. International Organization for<br />

Standardization. 1990<br />

[3] Hatton L... Safer C - Developing Software for High-integrity and Safety-critical<br />

Systems. ISBN 0-07-707640-0. McGraw-Hill, 1994<br />

[4] ISO/IEC 9899:COR1:1995. Technical Corrigendum 1, 1995<br />

[5] ISO/IEC 9899:AMD1:1995. Amendment 1. 1995<br />

[6] ISO/IEC 9899:COR2:1996. Technical Corrigendum 2. 1996<br />

[7] ANSI X3.159-1989. Programming languages - C, American National Standards<br />

Institute. 1989<br />

[8] ISO/IEC 9899:1999. Programming languages - C. International Organization for<br />

Standardization, 1999<br />

[9] <strong>MISRA</strong> Development Guidelines for Vehicle Based Software, ISBN 0-9524156-0-7.<br />

Motor Industry Research Association. Nuneaton, November 1994<br />

[10] CRR80, The Use of Commercial Off-the-Shelf (COTS) Software in Safety Related<br />

Applications. ISBN 0-7176-0984-7, HSE Books '<br />

[11] ISO 9001:2000. Quality management systems - Requirements. International]<br />

Organization for Standardization. 2000<br />

[12] ISO 90003:<strong>2004</strong>. Software engineering - Guidelines for the application of ISO<br />

9001:2000 to computer software. International Organization for Standardization. <strong>2004</strong><br />

[13] The TickIT Guide. Using ISO 9001:2000 for Software Quality Management System<br />

Construction, Certification and Continual Improvement, Issue 5, British Standards<br />

Institution. 2001<br />

[14] Straker D.. C Style: Standards and Guidelines. ISBN 0-13-116898-3. Prentice Hall<br />

1991<br />

[15] Fenton N.E. and Pfleeger S.L., Software Metrics: A Rigorous and Practical Approach,<br />

2nd Edition. ISBN 0-534-95429-1. PWS. 1998<br />

[16] <strong>MISRA</strong> Report 5 Software Metrics. Motor Industry Research Association. Nuneaton.<br />

February 1995<br />

[17] <strong>MISRA</strong> Report 6 Verification and Validation. Motor Industry Research Association.<br />

Nuneaton. February 1995<br />

[18] Kemighan B.W.. Ritchie D.M.. The C programming language. 2nd edition, ISBN<br />

0-13-110362-8. Prentice Hall. 1988 (note: The 1st edition is not a suitable reference<br />

document as it does not describe ANSI/ISO C)<br />

[19] Koenig A., C Traps and Pitfalls, ISBN 0-201 -17928-8, Addison-Wesley, 1988<br />

66


[20] IEC 61508, Functional safety of electrical/electronic/programmable electronic<br />

safety-related systems. International Electrotechnical Commission, in 7 parts published<br />

between 1998 and 2000<br />

[21] ANSI/IEEE Std 754, IEEE Standard for Binary Floating-Point Arithmetic, 1985<br />

[22] ISO/IEC 10646:2003, Information technology - Universal Multiple-Octet Coded<br />

Character Set (UCS), International Organization for Standardization, 2003<br />

67


Appendix A: Summary of rules<br />

本 附 录 给 出 第 6 节 中 所 有 规 则 的 汇 总 。<br />

环 境<br />

1.1 (req) 所 有 代 码 都 必 须 遵 照 ISO 9899:1990 “Programming languages - C”, 由<br />

ISO/IEC 9899/COR1:1995 , ISO/IEC 9899/AMD1:1995 , 和 ISO/IEC<br />

9899/COR2:1996 修 订 。<br />

1.2 (req) 不 能 有 对 未 定 义 行 为 或 未 指 定 行 为 的 依 赖 性 。<br />

1.3 (req) 多 个 编 译 器 和 / 或 语 言 只 能 在 为 语 言 / 编 译 器 / 汇 编 器 所 适 合 的 目 标 代 码 定 义<br />

了 通 用 接 口 标 准 时 使 用 。<br />

1.4 (req) 编 译 器 / 链 接 器 要 确 保 31 个 有 效 字 符 和 大 小 写 敏 感 能 被 外 部 标 识 符 支 持 。<br />

1.5 (adv) 浮 点 应 用 应 该 适 应 于 已 定 义 的 浮 点 标 准<br />

语 言 扩 展<br />

2.1 (req) 汇 编 语 言 应 该 被 封 装 并 隔 离 。<br />

2.2 (req) 源 代 码 应 该 使 用 /*…*/ 类 型 的 注 释 。<br />

2.3 (req) 字 符 序 列 /* 不 应 出 现 在 注 释 中 。<br />

2.4 (adv) 代 码 段 不 应 被 “ 注 释 掉 ”(comment out)。<br />

文 档<br />

3.1 (req) 所 有 实 现 定 义 (implementation-defined) 的 行 为 的 使 用 都 应 该 文 档 化 。<br />

3.2 (req) 字 符 集 和 相 应 的 编 码 应 该 文 档 化 。<br />

3.3 (adv) 应 该 确 定 、 文 档 化 和 重 视 所 选 编 译 器 中 整 数 除 法 的 实 现 。<br />

3.4 (req) 所 有 #pragma 指 令 的 使 用 应 该 文 档 化 并 给 出 良 好 解 释 。<br />

3.5 (req) 如 果 做 为 其 他 特 性 的 支 撑 , 实 现 定 义 (implementation-defined) 的 行 为 和 位<br />

域 (bitfields) 集 合 应 当 文 档 化 。<br />

3.6 (req) 产 品 代 码 中 使 用 的 所 有 库 都 要 适 应 本 文 档 给 出 的 要 求 , 并 且 要 经 过 适 当 的<br />

验 证 。<br />

字 符 集<br />

4.1 (req) 只 能 使 用 ISO C 标 准 中 定 义 的 escape 序 列 。<br />

4.2 (req) 不 能 使 用 三 字 母 词 (trigraphs)。<br />

标 识 符<br />

5.1 (req) 标 识 符 ( 内 部 的 和 外 部 的 ) 的 有 效 字 符 不 能 多 于 31。<br />

5.2 (req) 具 有 内 部 作 用 域 的 标 识 符 不 应 使 用 与 具 有 外 部 作 用 域 的 标 识 符 相 同 的 名<br />

称 , 这 会 隐 藏 了 外 部 标 识 符 。<br />

5.3 (req) typedef 的 名 字 应 当 是 唯 一 的 标 识 符 。<br />

5.4 (req) 标 签 (tag) 名 称 必 须 是 唯 一 的 标 识 符 。<br />

5.5 (adv) 具 有 静 态 存 储 期 的 对 象 或 函 数 标 识 符 不 能 重 用 。<br />

5.6 (adv) 一 个 命 名 空 间 中 不 应 存 在 与 另 外 一 个 命 名 空 间 中 的 标 识 符 拼 写 相 同 的 标 识<br />

符 , 除 了 结 构 和 联 合 的 成 员 名 字 。<br />

5.7 (adv) 不 能 重 用 标 识 符 名 字 。<br />

68


类 型<br />

6.1 (req) 单 纯 的 char 类 型 应 该 只 用 做 存 储 和 使 用 字 符 值 。<br />

6.2 (req) signed char 和 unsigned char 类 型 应 该 只 用 做 存 储 和 使 用 数 字 值 。<br />

6.3 (adv) 应 该 使 用 指 示 了 大 小 和 符 号 的 typedef 以 代 替 基 本 类 型 。<br />

6.4 (req) 位 域 只 能 被 定 义 为 unsigned int 或 singed int 类 型 。<br />

6.5 (req) unsigned int 类 型 的 位 域 至 少 应 该 为 2 bits 长 度 。<br />

常 量<br />

7.1 (req) 不 应 使 用 八 进 制 常 量 ( 零 除 外 ) 和 八 进 制 escape 序 列 。<br />

声 明 与 定 义<br />

8.1 (req) 函 数 应 当 具 有 原 型 声 明 , 且 原 型 在 函 数 的 定 义 和 调 用 范 围 内 都 是 可 见 的 。<br />

8.2 (req) 不 论 何 时 声 明 或 定 义 了 一 个 对 象 或 函 数 , 它 的 类 型 都 应 显 式 声 明 。<br />

8.3 (req) 函 数 的 每 个 参 数 类 型 在 声 明 和 定 义 中 必 须 是 等 同 的 , 函 数 的 返 回 类 型 也 该<br />

是 等 同 的 。<br />

8.4 (req) 如 果 对 象 或 函 数 被 声 明 了 多 次 , 那 么 它 们 的 类 型 应 该 是 兼 容 的 。<br />

8.5 (req) 头 文 件 中 不 应 有 对 象 或 函 数 的 定 义 。<br />

8.6 (req) 函 数 应 该 声 明 为 具 有 文 件 作 用 域 。<br />

8.7 (req) 如 果 对 象 的 访 问 只 是 在 单 一 的 函 数 中 , 那 么 对 象 应 该 声 明 在 块 范 围 内 声 明 。<br />

8.8 (req) 外 部 对 象 或 函 数 应 该 声 明 在 唯 一 的 文 件 中 。<br />

8.9 (req) 具 有 外 部 链 接 的 标 识 符 应 该 具 有 准 确 的 外 部 定 义 。<br />

8.10 (req) 在 文 件 范 围 内 声 明 和 定 义 的 所 有 对 象 或 函 数 应 该 具 有 内 部 链 接 , 除 非 是 在<br />

需 要 外 部 链 接 的 情 况 下 。<br />

8.1l (req) static 存 储 类 标 识 符 具 有 内 部 链 接 的 对 象 和 函 数 的 定 义 和 声 明 。<br />

8.12 (req) 当 一 个 数 组 声 明 为 具 有 外 部 链 接 , 它 的 大 小 应 该 显 式 声 明 或 者 通 过 初 始 化<br />

进 行 隐 式 定 义 。<br />

初 始 化<br />

9.1 (req) 所 有 自 动 变 量 在 使 用 前 都 应 被 赋 值 。<br />

9.2 (req) 应 该 使 用 大 括 号 以 指 示 和 匹 配 数 组 和 结 构 的 非 零 初 始 化 构 造 。<br />

9.3 (req) 在 枚 举 列 表 中 ,“=” 不 能 显 式 用 于 除 首 元 素 之 外 的 元 素 上 , 除 非 所 有 的 元<br />

素 都 是 显 式 初 始 化 的 。<br />

数 值 类 型 转 换<br />

10.1 (req) 下 列 条 件 成 立 时 , 整 型 表 达 式 的 值 不 应 隐 式 转 换 为 不 同 的 基 本 类 型 :<br />

a) 转 换 不 是 带 符 号 的 向 更 宽 整 数 类 型 的 转 换 , 或 者<br />

b) 表 达 式 是 复 杂 表 达 式 , 或 者<br />

c) 表 达 式 不 是 常 量 而 是 函 数 参 数 , 或 者<br />

d) 表 达 式 不 是 常 量 而 是 返 回 的 表 达 式 。<br />

10.2 (req) 下 列 条 件 成 立 时 , 浮 点 类 型 表 达 式 的 值 不 应 隐 式 转 换 为 不 同 的 类 型 :<br />

a) 转 换 不 是 向 更 宽 浮 点 类 型 的 转 换 , 或 者<br />

b) 表 达 式 是 复 杂 表 达 式 , 或 者<br />

69


c) 表 达 式 是 函 数 参 数 , 或 者<br />

d) 表 达 式 是 返 回 表 达 式 。<br />

10.3 (req) 整 型 复 杂 表 达 式 的 值 只 能 强 制 转 换 到 更 窄 的 类 型 且 与 表 达 式 的 基 本 类 型 具<br />

有 相 同 的 符 号 。<br />

10.4 (req) 浮 点 类 型 复 杂 表 达 式 的 值 只 能 强 制 转 换 到 更 窄 的 浮 点 类 型 。<br />

10.5 (req) 如 果 位 运 算 符 ~ 和


13.6 (req) for 循 环 中 用 于 迭 代 计 数 的 数 值 变 量 不 应 在 循 环 体 中 修 改 。<br />

13.7 (req) 不 允 许 进 行 结 果 不 会 改 变 的 布 尔 运 算 。<br />

控 制 流<br />

14.1 (req) 不 能 有 不 可 到 达 (unreachable) 的 代 码 。<br />

14.2 (req) 所 有 非 空 语 句 (non-null statement) 应 该 :<br />

a) 不 管 怎 样 执 行 都 至 少 有 一 个 副 作 用 (side-effect), 或 者<br />

b) 可 以 引 起 控 制 流 的 转 移<br />

14.3 (req) 在 预 处 理 之 前 , 空 语 句 只 能 出 现 在 一 行 上 ; 其 后 可 以 跟 有 注 释 , 假 设 紧 跟<br />

空 语 句 的 第 一 个 字 符 是 空 格 。<br />

14.4 (req) 不 应 使 用 goto 语 句 。<br />

14.5 (req) 不 应 使 用 continue 语 句 。<br />

14.6 (req) 对 任 何 迭 代 语 句 至 多 只 应 有 一 条 break 语 句 用 于 循 环 的 结 束 。<br />

14.7 (req) 一 个 函 数 在 其 结 尾 应 该 有 单 一 的 退 出 点 。<br />

14.8 (req) 组 成 switch、while、do...while 或 for 结 构 体 的 语 句 应 该 是 复 合 语 句 。<br />

14.9 (req) if( 表 达 式 ) 结 构 应 该 跟 随 有 复 合 语 句 。else 关 键 字 应 该 跟 随 有 复 合 语 句 或<br />

者 另 外 的 if 语 句 。<br />

14.10 (req) 所 有 的 if ... else if 结 构 应 该 由 else 子 句 结 束 。<br />

Switch 语 句<br />

15.1 (req) switch 标 签 只 能 用 在 当 最 紧 密 封 闭 (closely-enclosing) 的 复 合 语 句 是 switch<br />

语 句 体 的 时 候<br />

15.2 (req) 无 条 件 的 break 语 句 应 该 终 止 每 个 非 空 的 switch 子 句 。<br />

15.3 (req) switch 语 句 的 最 后 子 句 应 该 是 default 子 句 。<br />

15.4 (req) switch 表 达 式 不 应 是 有 效 的 布 尔 值 。<br />

15.5 (req) 每 个 switch 语 句 至 少 应 有 一 个 case 子 句 。<br />

函 数<br />

16.1 (req) 函 数 定 义 不 得 带 有 可 变 数 量 的 参 数<br />

16.2 (req) 函 数 不 能 调 用 自 身 , 不 管 是 直 接 还 是 间 接 的 。<br />

16.3 (req) 在 函 数 的 原 型 声 明 中 应 该 为 所 有 参 数 给 出 标 识 符<br />

16.4 (req) 函 数 的 声 明 和 定 义 中 使 用 的 标 识 符 应 该 一 致<br />

16.5 (req) 不 带 参 数 的 函 数 应 当 声 明 为 具 有 void 类 型 的 参 数<br />

16.6 (req) 传 递 给 一 个 函 数 的 参 数 应 该 与 声 明 的 参 数 匹 配 。<br />

16.7 (adv) 函 数 原 型 中 的 指 针 参 数 如 果 不 是 用 于 修 改 所 指 向 的 对 象 , 就 应 该 声 明 为 指<br />

向 const 的 指 针 。<br />

16.8 (req) 带 有 non-void 返 回 类 型 的 函 数 其 所 有 退 出 路 径 都 应 具 有 显 式 的 带 表 达 式 的<br />

return 语 句 。<br />

16.9(req)<br />

函 数 标 识 符 的 使 用 只 能 或 者 加 前 缀 &, 或 者 使 用 括 起 来 的 参 数 列 表 , 列 表 可<br />

以 为 空 。<br />

16.10 (req) 如 果 函 数 返 回 了 错 误 信 息 , 那 么 错 误 信 息 应 该 进 行 测 试 。<br />

指 针 和 数 组<br />

71


17.1 (req) 指 针 的 数 学 运 算 只 能 用 在 指 向 数 组 或 数 组 元 素 的 指 针 上 。<br />

17.2 (req) 指 针 减 法 只 能 用 在 指 向 同 一 数 组 中 元 素 的 指 针 上 。<br />

17.3 (req) >、>=、


20.4 (req) 不 能 使 用 动 态 堆 的 内 存 分 配<br />

20.5 (req) 不 要 使 用 错 误 指 示 errno。<br />

20.6 (req) 不 应 使 用 库 中 的 宏 offsetof。<br />

20.7 (req) 不 应 使 用 setjmp 宏 和 longjmp 函 数<br />

20.8 (req) 不 应 使 用 信 号 处 理 工 具 <br />

20.9 (req) 在 产 品 代 码 中 不 应 使 用 输 入 / 输 出 库 。<br />

20.10 (req) 不 应 使 用 库 中 的 函 数 atof、atoi 和 atol。<br />

20.11 (req) 不 应 使 用 库 中 的 函 数 abort、exit、getenv 和 system。<br />

20.12 (req) 不 应 使 用 库 中 的 时 间 处 理 函 数 。<br />

运 行 时 错 误<br />

21.1 (req) 最 大 限 度 降 低 运 行 时 错 误 必 须 要 确 保 至 少 使 用 了 下 列 方 法 之 一 :<br />

a) 静 态 分 析 工 具 / 技 术 ;<br />

b) 动 态 分 析 工 具 / 技 术 ;<br />

c) 显 式 的 代 码 检 测 以 处 理 运 行 时 故 障<br />

73


Appendix B:<strong>MISRA</strong>-C :1998 到<br />

<strong>MISRA</strong>-C :<strong>2004</strong> 规 则 映 射<br />

<strong>MISRA</strong>-C :1998 <strong>MISRA</strong>-C :<strong>2004</strong> <strong>MISRA</strong>-C:<strong>2004</strong> 规 则<br />

1 (req) 1.1 (req) 所 有 代 码 都 必 须 遵 照 ISO 9899:1990<br />

"Programming languages - C" , 由 ISO/IEC<br />

9899/COR1:1995,ISO/IEC 9899/AMD1:1995,<br />

和 ISO/IEC 9899/COR2:1996 修 订 。<br />

1 (req) 1.2 (req) 不 能 有 对 未 定 义 行 为 或 未 指 定 行 为 的 依 赖 性 。<br />

1 (req) 2.2 (req) 源 代 码 应 该 使 用 /*…*/ 类 型 的 注 释 。<br />

1 (req) 3.1 (req) 所 有 实 现 定 义 (implementation-defined) 的 行 为<br />

的 使 用 都 应 该 文 档 化 。<br />

2 (adv) 1.3 (req) 多 个 编 译 器 和 / 或 语 言 只 能 在 为 语 言 / 编 译 器 / 汇<br />

编 器 所 适 合 的 目 标 代 码 定 义 了 通 用 接 口 标 准 时<br />

使 用 。<br />

3 (adv) 2.1 (req) 汇 编 语 言 应 该 被 封 装 并 隔 离 。<br />

4 (adv) 21.1 (req) 最 大 限 度 降 低 运 行 时 错 误 必 须 要 确 保 至 少 使 用<br />

了 下 列 方 法 之 一 :<br />

a) 静 态 分 析 工 具 / 技 术 ;<br />

b) 动 态 分 析 工 具 / 技 术 ;<br />

c) 显 式 的 代 码 检 测 以 处 理 运 行 时 故 障<br />

5 (req) 4.1 (req) 只 能 使 用 ISO C 标 准 中 定 义 的 escape 序 列 。<br />

6 (req) 3.2 (req) 字 符 集 和 相 应 的 编 码 应 该 文 档 化 。<br />

7 (req) 4.2 (req) 不 能 使 用 三 字 母 词 (trigraphs)。<br />

8 (req) 已 废 除<br />

9 (req) 2.3 (req) 字 符 序 列 /* 不 应 出 现 在 注 释 中 。<br />

10 (adv) 2.4 (adv) 代 码 段 不 应 被 " 注 释 掉 "(comment out)。<br />

11 (req) 1.4 (req) 编 译 器 / 链 接 器 要 确 保 31 个 有 效 字 符 和 大 小 写 敏<br />

感 能 被 外 部 标 识 符 支 持 。<br />

11 (req) 5.1 (req) 标 识 符 ( 内 部 的 和 外 部 的 ) 的 有 效 字 符 不 能 多<br />

于 31。<br />

12 (adv) 5.5 (adv) 具 有 静 态 存 储 期 的 对 象 或 函 数 标 识 符 不 能 重<br />

用 。<br />

12 (adv) 5.6 (adv) 一 个 命 名 空 间 中 不 应 存 在 与 另 外 一 个 命 名 空 间<br />

中 的 标 识 符 拼 写 相 同 的 标 识 符 , 除 了 结 构 和 联<br />

合 的 成 员 名 字 。<br />

12 (adv) 5.7 (adv) 不 能 重 用 标 识 符 名 字 。<br />

13 (adv) 6.3 (adv) 应 该 使 用 指 示 了 大 小 和 符 号 的 typedef 以 代 替 基<br />

本 类 型 。<br />

74


<strong>MISRA</strong>-C :1998 <strong>MISRA</strong>-C :<strong>2004</strong> <strong>MISRA</strong>-C:<strong>2004</strong> 规 则<br />

14 (req) 6.1 (req) 单 纯 的 char 类 型 应 该 只 用 做 存 储 和 使 用 字 符 值 。<br />

14 (req) 6.2 (req) signed char 和 unsigned char 类 型 应 该 只 用 做 存 储<br />

和 使 用 数 字 值 。<br />

15 (adv) 1.5 (adv) 浮 点 应 用 应 该 适 应 于 已 定 义 的 浮 点 标 准<br />

16 (req) 12.12 (req) 不 应 使 用 浮 点 数 的 基 本 (underlying) 的 位 表 示<br />

法 (bit representation)<br />

17 (req) 5.2 (req) typedef 的 名 字 应 当 是 唯 一 的 标 识 符<br />

18 (adv) 已 废 除<br />

19 (req) 7.1 (req) 不 应 使 用 八 进 制 常 量 ( 零 除 外 ) 和 八 进 制 escape<br />

序 列 。<br />

20 (req) 已 废 除<br />

21 (req) 5.2 (req) 具 有 内 部 作 用 域 的 标 识 符 不 应 使 用 与 具 有 外 部<br />

作 用 域 的 标 识 符 相 同 的 名 称 , 这 会 隐 藏 了 外 部<br />

标 识 符 。<br />

22 (adv) 8.7 (req) 如 果 对 象 的 访 问 只 是 在 单 一 的 函 数 中 , 那 么 对<br />

象 应 该 声 明 在 块 范 围 内 声 明 。<br />

23 (adv) 8.10 (req) 在 文 件 范 围 内 声 明 和 定 义 的 所 有 对 象 或 函 数 应<br />

该 具 有 内 部 链 接 , 除 非 是 在 需 要 外 部 链 接 的 情<br />

况 下 。<br />

24 (req) 8.11 (req) static 存 储 类 标 识 符 具 有 内 部 链 接 的 对 象 和 函 数<br />

的 定 义 和 声 明 。<br />

25 (req) 8.9 (req) 具 有 外 部 链 接 的 标 识 符 应 该 具 有 准 确 的 外 部 定<br />

义 。<br />

26 (req) 8.4 (req) 如 果 对 象 或 函 数 被 声 明 了 多 次 , 那 么 它 们 的 类<br />

型 应 该 是 兼 容 的 。<br />

27 (adv) 8.8 (req) 外 部 对 象 或 函 数 应 该 声 明 在 唯 一 的 文 件 中 。<br />

28 (adv) 已 废 除<br />

29 (req) 5.4 (req) 标 签 (tag) 名 称 必 须 是 唯 一 的 标 识 符 。<br />

30 (req) 9.1 (req) 所 有 自 动 变 量 在 使 用 前 都 应 被 赋 值 。<br />

31 (req) 9.2 (req) 应 该 使 用 大 括 号 以 指 示 和 匹 配 数 组 和 结 构 的 非<br />

零 初 始 化 构 造 。<br />

32 (req) 9.3 (req) 在 枚 举 列 表 中 ,"=" 不 能 显 式 用 于 除 首 元 素 之 外<br />

的 元 素 上 , 除 非 所 有 的 元 素 都 是 显 式 初 始 化 的 。<br />

33 (req) 12.4 (req) 逻 辑 运 算 符 && 或 | | 的 右 手 操 作 数 不 能 包 含<br />

副 作 用 。<br />

34 (req) 12.5 (req) 逻 辑 && 或 | | 的 操 作 数 应 该 是<br />

primary-expressions。<br />

35 (req) 13.1 (req) 赋 值 运 算 符 不 能 使 用 在 产 生 布 尔 值 的 表 达 式<br />

上 。<br />

75


<strong>MISRA</strong>-C :1998 <strong>MISRA</strong>-C :<strong>2004</strong> <strong>MISRA</strong>-C:<strong>2004</strong> 规 则<br />

36 (adv) 12.6 (adv) 逻 辑 运 算 符 (&&、| | 和 !) 的 操 作 数 应 该 是 有<br />

效 的 布 尔 数 。 有 效 布 尔 类 型 的 表 达 式 不 能 用 做<br />

非 逻 辑 运 算 符 (&&、| | 和 !) 的 操 作 数<br />

37 (req) 10.5 (req) 如 果 位 运 算 符 ~ 和


<strong>MISRA</strong>-C :1998 <strong>MISRA</strong>-C :<strong>2004</strong> <strong>MISRA</strong>-C:<strong>2004</strong> 规 则<br />

49 (adv) 13.1 (adv) 数 的 非 零 检 测 应 该 明 确 给 出 , 除 非 操 作 数 是 有<br />

效 的 布 尔 类 型 。<br />

50 (req) 13.2 (req) 浮 点 表 达 式 不 能 做 相 等 或 不 等 的 检 测 。<br />

51 (adv) 12.11 (adv) 无 符 号 整 型 常 量 表 达 式 的 计 算 不 应 产 生 折 叠<br />

(wrap-around)。<br />

52 (req) 14.1 (req) 不 能 有 不 可 到 达 (unreachable) 的 代 码 。<br />

53 (req) 14.2 (req) 所 有 非 空 语 句 (non-null statement) 应 该 :<br />

a) 不 管 怎 样 执 行 都 至 少 有 一 个 副 作 用<br />

(side-effect), 或 者<br />

b) 可 以 引 起 控 制 流 的 转 移<br />

54 (req) 14.3 (req) 在 预 处 理 之 前 , 空 语 句 只 能 出 现 在 一 行 上 ; 其<br />

后 可 以 跟 有 注 释 , 假 设 紧 跟 空 语 句 的 第 一 个 字<br />

符 是 空 格 。<br />

55 (adv) 已 废 除<br />

56 (req) 14.4 (req) 不 应 使 用 goto 语 句 。<br />

57 (req) 14.5 (req) 不 应 使 用 continue 语 句 。<br />

58 (req) 已 废 除<br />

59 (req) 14.8 (req) 组 成 switch、while、do...while 或 for 结 构 体 的 语<br />

句 应 该 是 复 合 语 句 。<br />

59 (req) 14.9 (req) if( 表 达 式 ) 结 构 应 该 跟 随 有 复 合 语 句 。else 关<br />

键 字 应 该 跟 随 有 复 合 语 句 或 者 另 外 的 if 语 句 。<br />

60 (adv) 14.10 (req) 所 有 的 if ... else if 结 构 应 该 由 else 子 句 结 束 。<br />

61 (req) 15.1 (req) switch 标 签 只 能 用 在 当 最 紧 密 封 闭<br />

(closely-enclosing) 的 复 合 语 句 是 switch 语 句 体<br />

的 时 候<br />

61 (req) 15.2 (req) 无 条 件 的 break 语 句 应 该 终 止 每 个 非 空 的 switch<br />

子 句 。<br />

62 (req) 15.3 (req) switch 语 句 的 最 后 子 句 应 该 是 default 子 句 。<br />

63 (adv) 15.4 (req) switch 表 达 式 不 应 是 有 效 的 布 尔 值 。<br />

64 (req) 15.5 (req) 每 个 switch 语 句 至 少 应 有 一 个 case 子 句 。<br />

65 (req) 13.4 (req) for 语 句 的 控 制 表 达 式 不 能 包 含 任 何 浮 点 类 型 的<br />

对 象 。<br />

66 (adv) 13.5 (req) for 语 句 的 三 个 表 达 式 应 该 只 关 注 循 环 控 制 。<br />

67 (adv) 13.6 (req) for 循 环 中 用 于 迭 代 计 数 的 数 值 变 量 不 应 在 循 环<br />

体 中 修 改 。<br />

68 (req) 8.6 (req) 函 数 应 该 声 明 为 具 有 文 件 作 用 域 。<br />

69 (req) 16.1 (req) 函 数 定 义 不 得 带 有 可 变 数 量 的 参 数<br />

70 (req) 16.2 (req) 函 数 不 能 调 用 自 身 , 不 管 是 直 接 还 是 间 接 的 。<br />

71 (req) 8.1 (req) 函 数 应 当 具 有 原 型 声 明 , 且 原 型 在 函 数 的 定 义<br />

77


<strong>MISRA</strong>-C :1998 <strong>MISRA</strong>-C :<strong>2004</strong> <strong>MISRA</strong>-C:<strong>2004</strong> 规 则<br />

和 调 用 范 围 内 都 是 可 见 的 。<br />

72 (req) 8.3 (req) 函 数 的 每 个 参 数 类 型 在 声 明 和 定 义 中 必 须 是 等<br />

同 的 , 函 数 的 返 回 类 型 也 该 是 等 同 的 。<br />

73 (req) 16.3 (req) 在 函 数 的 原 型 声 明 中 应 该 为 所 有 参 数 给 出 标 识<br />

符<br />

74 (req) 16.4 (req) 函 数 的 声 明 和 定 义 中 使 用 的 标 识 符 应 该 一 致<br />

75 (req) 8.2 (req) 不 论 何 时 声 明 或 定 义 了 一 个 对 象 或 函 数 , 它 的<br />

类 型 都 应 显 式 声 明 。<br />

76 (req) 16.5 (req) 不 带 参 数 的 函 数 应 当 声 明 为 具 有 void 类 型 的 参<br />

数<br />

77 (req) 10.2 (req) 下 列 条 件 成 立 时 , 浮 点 类 型 表 达 式 的 值 不 应 隐<br />

式 转 换 为 不 同 的 类 型 :<br />

a) 转 换 不 是 向 更 宽 浮 点 类 型 的 转 换 , 或 者<br />

b) 表 达 式 是 复 杂 表 达 式 , 或 者<br />

c) 表 达 式 是 函 数 参 数 , 或 者<br />

d) 表 达 式 是 返 回 表 达 式 。<br />

78 (req) 16.6 (req) 传 递 给 一 个 函 数 的 参 数 应 该 与 声 明 的 参 数 匹<br />

配 。<br />

79 (req) 已 废 除<br />

80 (req) 已 废 除<br />

81 (adv) 16.7 (adv) 函 数 原 型 中 的 指 针 参 数 如 果 不 是 用 于 修 改 所 指<br />

向 的 对 象 , 就 应 该 声 明 为 指 向 const 的 指 针 。<br />

82 (adv) 14.7 (req) 一 个 函 数 在 其 结 尾 应 该 有 单 一 的 退 出 点 。<br />

83 (req) 16.8 (req) 带 有 non-void 返 回 类 型 的 函 数 其 所 有 退 出 路 径<br />

都 应 具 有 显 式 的 带 表 达 式 的 return 语 句 。<br />

84 (req) Rescinded 已 废 除<br />

85 (adv) 16.9 (req) 函 数 标 识 符 的 使 用 只 能 或 者 加 前 缀 &, 或 者 使 用<br />

括 起 来 的 参 数 列 表 , 列 表 可 以 为 空 。<br />

86 (adv) 16.10 (req) 如 果 函 数 返 回 了 错 误 信 息 , 那 么 错 误 信 息 应 该<br />

进 行 测 试 。<br />

87 (req) 8.5 (req) 头 文 件 中 不 应 有 对 象 或 函 数 的 定 义 。<br />

87 (req) 19.1 (adv) 文 件 中 的 #include 语 句 之 前 只 能 是 其 他 预 处 理<br />

指 令 或 注 释 。<br />

88 (req) 19.2 (adv) #include 指 令 中 的 头 文 件 名 字 里 不 能 出 现 非 标<br />

准 字 符 。<br />

89 (req) 19.3 (req) #include 预 处 理 指 令 应 该 跟 随 或<br />

"filename" 序 列 。<br />

90 (req) 19.4 (req) C 的 宏 只 能 扩 展 为 用 大 括 号 括 起 来 的 初 始 化 、 常<br />

量 、 小 括 号 括 起 来 的 表 达 式 、 类 型 限 定 符 、 存<br />

储 类 标 识 符 或 do-while-zero 结 构 。<br />

78


<strong>MISRA</strong>-C :1998 <strong>MISRA</strong>-C :<strong>2004</strong> <strong>MISRA</strong>-C:<strong>2004</strong> 规 则<br />

91 (req) 19.5 (req) 宏 不 能 在 块 中 进 行 #define 和 #undef。<br />

92 (adv) 19.6 (req) 不 要 使 用 #undef。<br />

93 (adv) 19.7 (adv) 函 数 的 使 用 优 先 选 择 函 数 宏 。<br />

94 (req) 19.8 (req) 函 数 宏 的 调 用 不 能 缺 少 参 数<br />

95 (req) 19.9 (req) 传 递 给 函 数 宏 的 参 数 不 能 包 含 看 似 预 处 理 指 令<br />

的 标 记 。<br />

96 (req) 19.10 (req) 在 定 义 函 数 宏 时 , 每 个 参 数 实 例 都 应 该 以 小 括<br />

号 括 起 来 , 除 非 它 们 做 为 # 或 ## 的 操 作 数 。<br />

97 (adv) 19.11 (req) 预 处 理 指 令 中 所 有 宏 标 识 符 在 使 用 前 都 应 先 定<br />

义 , 除 了 #ifdef 和 #ifndef 指 令 及 defined() 操 作 符 。<br />

98 (req) 19.12 (req) 在 单 一 的 宏 定 义 中 最 多 可 以 出 现 一 次 # 或 ##<br />

预 处 理 器 操 作 符 。<br />

98 (req) 19.13 (adv) 不 要 使 用 # 或 ## 预 处 理 器 操 作 符 。<br />

99 (req) 3.4 (req) 所 有 #pragma 指 令 的 使 用 应 该 文 档 化 并 给 出 良<br />

好 解 释 。<br />

100 (req) 19.14 (req) defined 预 处 理 操 作 符 只 能 使 用 两 种 标 准 形 式 之<br />

一 。<br />

101 (adv) 17.1 (req) 指 针 的 数 学 运 算 只 能 用 在 指 向 数 组 或 数 组 元 素<br />

的 指 针 上 。<br />

101 (adv) 17.2 (req) 指 针 减 法 只 能 用 在 指 向 同 一 数 组 中 元 素 的 指 针<br />

上 。<br />

101 (adv) 17.4 (req) 数 组 的 索 引 应 当 是 指 针 数 学 运 算 的 唯 一 可 允 许<br />

的 方 式<br />

102 (adv) 17.5 (adv) 对 象 声 明 所 包 含 的 间 接 指 针 不 得 多 于 2 级<br />

103 (req) 17.3 (req) >、>=、


<strong>MISRA</strong>-C :1998 <strong>MISRA</strong>-C :<strong>2004</strong> <strong>MISRA</strong>-C:<strong>2004</strong> 规 则<br />

114 (req) 20.1 (req) 标 准 库 中 保 留 的 标 识 符 、 宏 和 函 数 不 能 被 定 义 、<br />

重 定 义 或 取 消 定 义 。<br />

115 (req) 20.2 (req) 不 能 重 用 标 准 库 中 宏 、 对 象 和 函 数 的 名 字 。<br />

116 (req) 3.6 (req) 产 品 代 码 中 使 用 的 所 有 库 都 要 适 应 本 文 档 给 出<br />

的 要 求 , 并 且 要 经 过 适 当 的 验 证 。<br />

117 (req) 20.3 (req) 传 递 给 库 函 数 的 值 必 须 检 查 其 有 效 性 。<br />

118 (req) 20.4 (req) 不 能 使 用 动 态 堆 的 内 存 分 配<br />

119 (req) 20.5 (req) 不 要 使 用 错 误 指 示 errno。<br />

120 (req) 20.6 (req) 不 应 使 用 库 中 的 宏 offsetof。<br />

121 (req) 已 废 除<br />

122 (req) 20.7 (req) 不 应 使 用 setjmp 宏 和 longjmp 函 数<br />

123 (req) 20.8 (req) 不 应 使 用 信 号 处 理 工 具 <br />

124 (req) 20.9 (req) 在 产 品 代 码 中 不 应 使 用 输 入 / 输 出 库 。<br />

125 (req) 20.10 (req) 不 应 使 用 库 中 的 函 数 atof、atoi 和 atol。<br />

126 (req) 20.11 (req) 不 应 使 用 库 中 的 函 数 abort、exit、getenv<br />

和 system。<br />

127 (req) 20.12 (req) 不 应 使 用 库 中 的 时 间 处 理 函 数 。<br />

80


Appendix C:<strong>MISRA</strong>-C:1998 – 已 废 除 的 规 则<br />

Rule 8 (rescinded):<br />

Rule 18 (rescinded):<br />

Rule 20 (rescinded):<br />

Rule 28 (rescinded):<br />

Rule 44 (rescinded):<br />

Rule 55 (rescinded):<br />

Rule 58 (rescinded):<br />

Rule 79 (rescinded):<br />

Rule 80 (rescinded):<br />

Rule 84 (rescinded):<br />

Rule 104 (rescinded):<br />

Rule 105 (rescinded):<br />

Rule 107 (rescinded):<br />

Rule 113 (rescinded):<br />

Rule 121 (rescinded):<br />

Multibyte characters and wide string literals shall not be used.<br />

Integer constants should be suffixed to reflect their type where an<br />

appropriate suffix is available.<br />

All object and function identifiers shall be declared before use.<br />

The register storage class specifier should not be used.<br />

Redundant explicit casts should not be used.<br />

Labels should not be used, except in switch statements.<br />

The break statement shall not be used (except to terminate the cases of<br />

a switch statement).<br />

The values returned by void functions shall not be used.<br />

Void expressions shall not be passed as function parameters.<br />

For functions with void return type, return statements shall not have an<br />

expression.<br />

Non-constant pointers to functions shall not be used.<br />

All the functions pointed to by a single pointer to function shall be<br />

identical in the number and type of parameters and the return type.<br />

The null pointer shall not be de-referenced.<br />

All the members of a structure (or union) shall be named and shall<br />

only be accessed via their name.<br />

and the setlocale function shall not be used.<br />

81


Appendix D:ISO 标 准 交 互 参 考<br />

本 附 录 给 出 文 档 中 提 供 的 规 则 与 ISO 9899[2] 的 对 应 关 系 。<br />

D1. <strong>MISRA</strong>-C :<strong>2004</strong> 规 则 序 号 与 ISO 9899 的 对 应 关 系<br />

Rule ISO ref Rule ISO ref Rule ISO ref<br />

1.4 6.1.2 8.2 6.5.4 12.1 6.3<br />

1.5 6.1.2.5 83 6.5.4.3,6.7.1 12.2 5.1.2.3, 6.3,<br />

6.6<br />

2.2 6.1.9 8.4 6.1.2.6,6.5 123 5.1.2.3,6.3.3.4<br />

2.3 6.1.9 8.5 6.8.2 12.4 5.1.2.3,6.3.13,<br />

2.4 6.1.9 8.6 6.1.2.1, 6.5.4.3 6.3.14<br />

33 6.3.5 8.7 6.1.2.1,6.5 12.5 6.3.1,6.3.13,<br />

3.4 6.8.6 8.8 6.7 6.3.14<br />

3.5 6.5.2.1 8.9 6.7 12.6 6.3.3.3,6.3.13,<br />

4.1 52.2 8.10 6.1.2.1,6.1.2.2, 6.3.14<br />

4.2 5.2.1.1 6.5.4 12.7 6.3.3.3, 6.3.7,<br />

5.1 6.1.2 8.11 6.1.2.2,6.5.1, 6.3.10,63.11<br />

5.2 6.1.2,1 6.5.4 6.3.12<br />

5.3 6.5.6 9.1 6.5.7 12.8 6.3.7<br />

5.4 6.5.2.3 9.2 6.5.7 12.9 6..3.3..3<br />

5.5 6.1.2.2 9.3 6.5.2.2 12.10 6.3.17<br />

5,6 6.1.2.3 10.1 6.2 12.11 6.4,'6.8.1<br />

5.7 6.1.2 10.2 6.2 12.12 5.2.4.2.2,<br />

6.1.2.5<br />

6.1 6.1.2.5 10.3 6.2, 6.3.4 12.13 6.3.2.4,6.3.3.1<br />

6.2 6.2.1.1 6.2, 6.3.4 13.1 6.3.16<br />

63 6.1.2.5,6.5.2, 10.5 6.3.33, 6.3.7 13.2 6.6.4.1,6.6.5<br />

6.5.6 10.6 6.1.3.2 133 5.2.4.2.2,<br />

6.3.9<br />

6.4 6.5.2.1 11.1 6.3.4 13.4 6.6.5.3<br />

6.5 6.5.2.1 11.2 6.3.4 134 6.6.5.3<br />

11.3 6.3.4 13.6 6.6.5.3<br />

7.1 6.1.3.2 11.4 6.3.4 14 2 5.1,23, 6.6.3<br />

8.1 6.3.2.2,<br />

6.5.4.3<br />

11.5 6.53 143 6.6.3<br />

14.4 6.6.6.1<br />

14.5 6.6.6.2 17.2 6.3.6, 6.3.16.2 19.12 6.8.3.2,<br />

6.8.3.3<br />

14.6 6.6.6.3 173 6.3.8 19.13 6.8.3.2,<br />

6.8.3.3<br />

14.7 6.6.6.4 17.4 6.3.2.1,6.3.6 19.14 6.8.1<br />

14.8 6.6.5 17.5 6.33.2, 6.5.4.1 19.15 6.8<br />

14.9 6.6.4.1 17.6 6.1.2.4,6.33.2 19.16 6.8<br />

14.10 6.6.4.1 1.8.1 6.1.2.5,6.5, 20.1 6.87,1.3.7.13<br />

15.1 6.6.4.2 6.5.2.1 20.2 7.1<br />

15.2 6.6.4.2, 1.8.2 6.3.16.1 20.3 7.17.3,7.5.1<br />

15.3 6.6.4.2 1.8.4 6.1.2.5,6.3.2.3, 7.5.6.4<br />

15.4 6.6.4.2 6.5.2.1 20.4 7.1<br />

15.5 6.6.4.2 19.1 6.8.2 20.5 7.17.5.1<br />

16.1 6.7.1, 19.2 6.1.7 20.6 7.1<br />

16.2 6.3.2.2 19.3 6.8.2 20.7 7.6<br />

16.3 6.5.4.3 19.4 6.8.3 20.8 7.7<br />

82


16.4 6.5.4.3 19.5 6.8.3,6.8.3.5 20.9 7.9<br />

16.5 6.5.4.3, 19.6 6.8.3.5 20.10 7.10.1<br />

16.6 6.3.2.2 19.7 6.8.3 20.11 7.10.4<br />

16.7 6.5.4.1, 19.8 6.8.3 20.12 7.12<br />

16.8 6.6.6.4 19.9 6.8.3 21.1 6.3.3.3.2,<br />

16.9 6.3.2.2, 19.10 6.8.3 7.1<br />

17.1 6.3.6, 19.11 6.8 21.2 7.1,<br />

83


D1.ISO 9899 参 考 与 <strong>MISRA</strong>-C :<strong>2004</strong> 规 则 序 号 的 对 应 关 系<br />

ISO ref Rule ISO ref Rule ISO ref Rule<br />

5.1.23 12.2, 123, 12.4, 6.3.6 17.1, 17.2, 6.6.5.3 13.4, 13.5,<br />

17.4<br />

14.2 6.3.7 10.5, 12.7, 6.6.6.1 14.4<br />

12.8<br />

5.2.2 4.1 6.3:8 17.3. 6.6.6.2 14.5<br />

5.2.1.1 4.2 6.3.9 13.3 6.6.6.3 14.6, 15.2<br />

5.2.4.2.2 12.12, 13.3 6.3.10 12.7 6.6.6.4 14.7, 16.8<br />

6.1.2 1.4,5.1,5.7 6.3.11 12.7 6.7 8.8, 8.9<br />

6.1.2.1 5.2,8.6,8.7,8.10 6.3.12 12.7 6.7.1 8.3, 16.1, 16<br />

6.U.2 5.5,8.10,8.11 6.3.13 12.4,12.5,<br />

16.5<br />

12.6<br />

6.1.2.3 5.6 6.3.14 12.4, 12.5, 6.8 19.11, 19.15<br />

12.6<br />

6.1.2.4 17.6 6.3.16 13.1 6.8.1 12.11, 19.14<br />

6.1.2.5 1.5,6.2,6.3, 6.3.16.1 18.2 6.8.2 8.5, 19.1, 19<br />

12.12, 18.1, 6.3.16.2 17.1, 17.2 6.8.3 19.4, 19.5,<br />

18.4<br />

6.1.2.6 8.4 6.3.17 12.10 19.7-10<br />

6.1.3.2 7.1, 10.6 6.4 12.11 6.83.2 19.12,19.13<br />

6.1.7 19.2 6.5 8.4, 8.7, 18.1 6.83.3 19.12, 1-9.13<br />

6.1.9 2.2, 2.3, 2.4 6.5.1 8.11- 6.8.3.5 19.5,19.6<br />

6.2 10.1, 10.2, 6.5.2 6.3 6.8.6 3.4<br />

10.3,<br />

10.4 6.5.2.1 3.5, 6.4, 6.5, 6.8.8 20.1<br />

6.2.1.1 6.1 18.1, 18.4 7.1.3 20.1, 20,2<br />

6.3 111,12.2,21.1 6.5:2.2 9.3<br />

7.1.6 20.6<br />

T"<br />

6.3.1 12.5 6.5.2.3 5.4 7.1.7 20.3<br />

6.3.2.1 17.4 6.5.3 11.5 73 20.3<br />

6.3.2.2 8.1,16.2, 16.6. 6.5.4 8.2,8.10,8.11 7.5.1 20.3, 20.5<br />

16.9 6.5.4.1 16:7, 17.5 7.5.6.4 20.3<br />

6.3.2.3 18.4 6.5.4.3 8.1, 8.2,8.3; 7.6 20.7<br />

8.6,<br />

6.3.2.4 12.13 16.3, 16.4, 7.7 20.8<br />

16.5,<br />

6.3.3.1 12.13 16.7 7.8 16.1<br />

6.33.2 16.9, 17.5, 6.5.6 5.3, 6.3 7.9 20.9<br />

17.6,<br />

21.1 6.5.7 9.1,9.2-.. 7.10.1 20.10<br />

6.3.3.3 10.5, 12.6, 6.6 12.2 7.10.3 20.4<br />

12.7,<br />

12.9 6.6.3 14.2,14.3 7.10.6 21.1<br />

6.3.3.4 12.3 6.6.4.1 13.2, 14.9, 7.12 20.12<br />

14.10<br />

6.3.4 10.3,10.4, 11.1, 6.6.4.2 15.1 - 15.5 7.13 20.1<br />

11.2, 11.3, 11.4 6.6.5 13.2, 14.8<br />

6.3.5 3.3<br />

84


Appendix E : 术 语 表<br />

基 本 类 型 (Underlying type)<br />

见 6.10.4 节 “ 基 本 类 型 ”<br />

规 则 范 围<br />

<strong>MISRA</strong> 规 则 适 用 于 工 程 项 目 中 的 所 有 源 文 件 。 即 :<br />

• 由 项 目 小 组 编 写 的 文 件<br />

• 所 有 由 其 他 小 组 和 副 代 理 商 提 供 的 文 件<br />

• 编 译 器 库 的 头 文 件 , 但 不 是 库 文 件 , 后 者 只 做 为 目 标 代 码<br />

• 所 有 第 三 方 的 库 资 源 , 特 别 是 头 文 件<br />

要 认 识 到 , 在 获 得 第 三 方 资 源 符 合 规 则 标 准 时 可 能 会 有 些 问 题 , 但 许 多 工 具 和 库 的 供 应<br />

商 为 他 们 的 代 码 采 用 <strong>MISRA</strong>-C 做 为 标 准 。<br />

布 尔 表 达 式<br />

严 格 说 来 ,C 当 中 没 有 布 尔 类 型 , 但 返 回 数 值 类 型 的 表 达 式 和 返 回 布 尔 类 型 的 表 达 式 存 在<br />

着 概 念 上 的 差 异 。 一 个 表 达 式 表 示 了 布 尔 值 , 或 者 是 因 为 它 出 现 在 需 要 布 尔 值 的 地 方 , 或 者<br />

是 因 为 它 使 用 了 产 生 布 尔 值 的 运 算 符 。<br />

在 下 面 的 上 下 文 环 境 中 希 望 布 尔 值 :<br />

• if 语 句 的 控 制 表 达 式<br />

• 迭 代 语 句 的 控 制 表 达 式<br />

• 条 件 运 算 符 ? 的 第 一 个 操 作 数<br />

每 种 环 境 需 要 一 个 “ 有 效 布 尔 ” 表 达 式 , 或 者 是 “Boolean-by-construct ”, 或 者 是<br />

“Boolean-by-construct”, 定 义 如 下 :<br />

Boolean-by-contruct 值 由 以 下 运 算 符 产 生 :<br />

• 等 值 运 算 符 (== 和 !=)<br />

• 逻 辑 运 算 符 ( !,&& 和 ||)<br />

• 关 系 运 算 符 (,=)<br />

Boolean-by-enforcement 值 可 以 使 用 工 具 实 现 一 个 特 定 的 强 制 类 型 来 产 生 。 此 时 布 尔 类 型<br />

与 特 定 的 typedef 相 关 联 , 可 以 用 于 任 何 布 尔 对 象 。 这 可 以 带 来 许 多 好 处 , 尤 其 是 当 具 有 检 查<br />

工 具 的 支 持 时 , 而 且 , 在 某 些 特 殊 情 况 下 它 能 帮 助 避 免 逻 辑 运 算 和 整 数 运 算 之 间 的 混 淆 。<br />

短 整 型 (smaller integer type)<br />

术 语 “ 短 整 型 ” 用 来 描 述 那 些 服 从 整 数 提 升 (interger promotion) 的 整 数 类 型 。 受 整 数 提<br />

升 影 响 的 类 型 是 char,short,bit-field 和 enum。<br />

85

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!