第 4 章 表 达 式 和 赋 值
本 章 描 述 如 何 在 C 语 言 中 构 造 表 达 式 和 对 其 赋 值 。 常 量 、 标 识 符 、 字符 串 和 函 数 调 用 都 是 在 表 达 式 中 操 作 的 操 作 数 。 C 语 言 具 有 所 有 常 用 的语 言 运 算 符 。 本 章 讨 论 这 些 运 算 符 以 及 对 C 或 M icrosoft 是 唯 一 的 运 算符 。 讨 论 的 主 题 包 括 :
-
操 作 数 和 表 达 式
-
运 算 符
-
类 型 转 换
操 作 数 和 表 达 式
一 个 “ 操 作 数 ” 是 一 个 运 算 符 作 用 的 一 个 实 体 。 一 个 “ 表 达 式 ” 是 执 行这 些 动 作 的 任 何 组 合 的 运 算 符 和 操 作 数 序 列 :
-
计 算 一 个 值
-
设 计 一 个 对 象 或 函 数
-
产 生 副 作 用
在 C 中 的 操 作 数 包 括 常 量 、 标 识 符 、 字 符 串 、 函 数 调 用 、 下 标 表 达 式 、成 员 选 择 表 达 式 和 通 过 运 算 符 组 合 操 作 数 或 在 圆 括 号 中 包 括 操 作 数 而 形
成 的 复 杂 表 达 式 。 这 些 操 作 数 的 语 法 在 下 一 节 “ 基 本 表 达 式 ” 中 给 出 。
基 本 表 达 式
表达式中的操作数称为 “基本表达式 ”。
语法
基本表达式 :
标识符常量
字符串文字
(表达式 ) 表达式 :
赋值表达式
表达式 ,赋 值 表 达 式
基 本 表 达 式 中 的 标 识 符
标 识 符 有 整 数 、 float 、 enum 、 struct 、 union 、 数 组 、 指 针 或 函 数 类 型 。一 个 标 识 符 是 一 个 基 本 表 达 式 , 它 被 说 明 用 于 设 计 一 个 对 象 ( 这 种 情 况 下它 是 一 个 l 值 ) 或 一 个 函 数 ( 这 种 情 况 下 它 是 一 个 函 数 指 示 符 )。 有 关 l 值的 定 义 参 见 “ L 值 和 R 值 表 达 式 ”。
由 一 个 数 组 标 识 符 表 示 的 指 针 值 不 是 变 量 , 因 此 , 一 个 数 组 标 识 符 不 能 形成 一 个 赋 值 运 算 的 左 边 操 作 数 。 因 此 不 是 一 个 可 修 改 的 l 值 。
- 个 作 为 函 数 说 明 的 标 识 符 表 示 一 个 其 值 是 该 函 数 地 址
的 指 针 。 该 指 针
地 址 指 向 一 个 返 回 指 定 类 型 值 的 函 数 。 因 此 , 函 数 标 识 符 也 不 能 是 赋 值操 作 中 的 l 值 。 有 关 更 多 信 息 ,参 见 第 1 章 “ C 的 基 本 元 素 ” 中 的 “ 标 识符 ” 。
基 本 表 达 式 中 的 常 量
- 个 常 量 操 作 数 有 它 给 定 常 量 值 的 值 和 类 型 。 一 个 字 符 常 量 有 int 类 型 。一 个 整 数 常 量 有 in t、 long 、 unsigned int 或 unsigned long 类 型 ,这 取 决 于该 整 数 的 尺 寸 和 指 定 值 的 方 式 。 有 关 更 多 信 息 参 见 第 1 章 “ C 的 基 本 元素 ” 中 的 “ 常 量 ”。
基 本 表 达 式 中 的 字 符 串 文 字
- 个 “ 字 符 串 文 字 ” 是 一 个 字 符 、 宽 字 符 或 用 双 引 号 括 起 的 相 邻 字 符 序列 。 由 于 它 们 不 是 变 量 , 因 此 字 符 串 文 字 或 任 何 它 们 的 元 素 都 不 能 作 为一 个 赋 值 操 作 的 左 边 操 作 数 。 一 个 字 符 串 文 字 的 类 型 是 char 的 数 组 ( 或宽 字 符 串 文 字 的 wchar _ t 数 组 )。 在 表 达 式 中 数 组 都 转 换 成 指 针 。 有 关 字符 串 的 更 多 信 息 , 参 见 第 1 章 “ C 的 基 本 元 素 ” 的 “ 字 符 串 文 字 ”。
圆 括 号 中 的 表 达 式
你 可 以 在 圆 括 号 中 括 起 任 何 操 作 数 而 不 改 变 该 括 起 的 表 达 式 的 类 型 或值 。 例 如 ,在 表 达 式 中 :
(10+5)/5
圆 括 号 中 的 10+5 意 味 着 首 先 对 10+5 求 值 ,它 变 成 除 法 (/) 运 算 符 的 左 操
作 数 。 (10+5)/5 的 结 果 是 3 。 没 有 圆 括 号 的 10+5/5 的 结 果 是 11 。
虽 然 圆 括 号 影 响 一 个 表 达 式 中 组 合 操 作 数 的 方 式 , 它 们 不 能 保 证 在 所 有情 况 下 的 一 个 特 殊 求 值 次 序 。 例 如 , 如 下 表 达 式 的 圆 括 号 和 从 左 到 右 的组 合 都 不 能 保 证 i 在 每 个 子 表 达 式 中 是 什 么 样 的 值 。
(i++ +1)*(2+i)
编 译 器 自 由 以 任 何 次 序 计 算 乘 法 两 边 的 值 。 如 果 i 的 初 值 为 0, 整 个 表 达式 以 如 下 两 个 语 句 求 值 :
(0+1+1)*(2+1)
(0+1+1)*(2+0)
副 作 用 导 致 的 异 常 在 本 章 后 面 “ 副 作 用 ” 中 讨 论 。
L 值 和 R 值 表 达 式
指 的 是 存 储 器 位 置 的 表 达 式 称 为 “ l 值 ” 表 达 式 , 一 个 l 值 表 示 一 个 存 储区 域 的 “ 定 位 器 ” 值 或 “ 左 边 ” 值 ,它 隐 含 出 现 在 等 号 (= )的 左 边 。 l 值 经常 是 标 识 符 。
指 的 是 右 修 改 的 位 置 的 表 达 式 称 为 “ 可 修 改 的 l 值 ”。 一 个 可 修 改 的 l 值不 能 有 一 个 数 组 类 型 , 一 个 不 完 整 类 型 或 具 有 const 属 性 的 类 型 , 对 于 可以 是 可 修 改 l 值 的 结 构 和 联 合 ,它 们 必 须 没 有 const 属 性 的 成 员 。 标 识 符的 名 称 指 示 一 个 存 储 位 置 , 而 该 变 量 的 值 是 存 储 在 该 位 置 的 值 。
如 果 一 个 标 识 符 指 向 一 个 存 储 器 位 置 , 其 类 型 是 算 术 、 结 构 、 联 合 或 指针 ,则 该 标 识 符 是 一 个 可 修 改 的 l 值 。 例 如 ,如 果 ptr 是 一 个 存 储 区 域 的 指针 ,那 么 *ptr 是 一 个 可 修 改 的 l 值 , 指 示 该 存 储 区 域 由 ptr 指 向 。
如 下 任 何 C 表 达 式 可 以 是 l 值 表 达 式 :
-
一 个 整 数 、 浮 点 、 指 针 、 结 构 或 联 合 类 型 的 标 识 符 。
-
一 个 不 对 数 组 求 值 的 下 标 ([]) 表 达 式 。
-
一 个 成 员 选 择 表 达 式 (-> 或 .)
-
一 个 不 指 向 一 个 数 组 的 单 目 间 接 访 问 (*) 表 达 式 。
-
一 个 圆 括 号 中 的 l 值 表 达 式 。
-
一 个 const 对 象 ( 一 个 不 能 修 改 的 l 值 ) 。
本 语 “ r 值 ” 有 时 用 来 描 述 一 个 表 达 式 的 值 以 区 别 于 一 个 l 值 。 所 有 l
值 都 是 r 值 ,但 不 是 所 有 r 值 都 是 l 值 。
Microsoft 特 殊 处 →
C 包括 ANSI C 标 准 的 一 个 扩 充 是 允 许 l 值 造 型 用 作 l 值 ,以 及 该 对 象 的尺 寸 不 会 通 过 该 造 型 而 伸 长 ( 有 关 更 多 信 息 , 参 见 本 章 末 尾 的 “ 类 型 造 型转 换 ” )。 如 下 例 子 说 明 了 这 种 特 征 :
char *p; short i; long l;
(long *) p=&l; /* 合法造型 */ (long) i=l; /* 非法造型 */
C 缺 省 能 使 M icrosoft 扩 充 。 使 用 /Za 编 译 器 选 项 禁 止 这 种 扩 充 。
Microsoft 特 殊 处 结 束
常 量 表 达 式
- 个 常 量 表 达 式 在 编 译 时 求 值 , 而 不 是 在 运 行 时 求 值 , 可 以 使 用 在 一 个 常量 可 以 被 使 用 的 任 何 地 方 。 常 量 表 达 式 必 须 求 值 为 一 个 在 该 类 型 可 表 示值 的 范 围 内 的 常 量 。 一 个 常 量 表 达 式 的 操 作 数 可 以 是 整 数 常 量 、 字 符 常量 、 浮 点 常 量 、 枚 举 常 量 、 类 型 造 型 、 size o f 表 达 式 和 其 它 常 量 表 达 式 。
语法
常量表达式 :
条件表达式条件表达式 :
逻辑 O R 表达式
逻辑 O R 表达式 ? 表达式 : 条件表达式表达式 :
赋值表达式
表达式 ,赋 值 表 达 式赋值表达式 :
条件表达式
单目表达式 赋值运算符 赋值表达式
赋 值 运 算 符 :如 下 之 一 :
= *= /= %= += -= <<= >>= &= ^= |=
结 构 说 明 符 、 枚 举 器 、 直 接 说 明 符 、 直 接 抽 象 说 明 符 和 标 号 语 句 的 非 终结 符 包 含 常 量 表 达 式 非 终 结 符 。
一 个 整 数 常 量 表 达 式 必 须 用 于 指 定 一 个 结 构 位 域 成 员 的 尺 寸 、 一 个 枚 举常 量 的 值 、 一 个 数 组 的 尺 寸 或 一 个 case 常 量 的 值 。
用 在 预 处 理 器 命 令 中 的 常 量 表 达 式 满 足 一 些 附 加 限 制 。 结 果 它 们 是 众 所周 知 的 “ 限 制 的 常 量 表 达 式 ”。 一 个 限 制 的 常 量 表 达 式 不 能 包 含 sizeof 表 达 式 、 枚 举 常 量 、 到 任 何 类 型 的 类 型 造 型 或 浮 点 类 型 常 量 。 但 它 可 以包 含 定 义 的 特 定 常 量 表 达 式 ( 标 识 符 )。
表 达 式 求 值
涉 及 赋 值 、 单 目 增 1 、 单 目 减 1 或 调 用 一 个 函 数 的 表 达 式 具 有 伴 随 它 们求 值 的 结 果 ( 副 作 用 ), 当 到 达 一 个 “ 顺 序 点 ” 时 , 该 顺 序 点 之 前 的 任 何 事情 包 括 任 何 副 作 用 都 保 证 在 开 始 计 算 该 顺 序 点 之 后 的 任 何 事 情 之 前 进 行求 值 。
通 过 对 一 个 表 达 式 求 值 导 致 改 变 “ 副 作 用 ”。 副 作 用 出 现 在 一 个 变 量 的值 被 一 个 表 达 式 求 值 所 改 变 的 任 何 时 候 。 所 有 赋 值 操 作 都 有 副 作 用 。 如果 函 数 调 用 通 过 直 接 赋 值 或 使 用 一 个 指 针 间 接 赋 值 来 改 变 一 个 外 部 的 可见 项 的 值 ,则 该 函 数 调 用 也 有 副 作 用 。
副 作 用
- 个 表 达 式 的 求 值 次 序 是 由 指 定 的 实 现 确 定 的 , 除 了 当 该 语 言 保 证 一 个特 殊 的 求 值 次 序 外 ( 正 如 本 章 后 面 的 “ 优 先 级 和 求 值 次 序 ” 中 描 述 的 )。例 如 , 在 如 下 函 数 调 用 中 出 现 副 作 用 :
add(i+1,i=j+2);
myproc(getc(),getc());
- 个 函 数 调 用 的 参 量 可 以 以 任 何 次 序 求 值 。 表 达 式 i+1 可 以 在 i=j+2 之前 求 值 , 或者 i=j+2 可 以 在 i+1 之 前 求 值 ,每 种 情 况 下 的 结 果 是 不 同 的 ,同样 ,不 可 能 保 证 哪 个 字 符 实 际 传 送 给 myproc 。 由 于 单 目 增 1 和 减 1 操 作涉 及 到 赋 值 ,如 下 例 子 中 的 操 作 可 能 导 致 副 作 用 :
x[i]=i++;
在 这 个 例 子 中 , 被 修 改 的 x 的 值 是 不 可 预 料 的 。 下 标 的 值 可 以 是 i 的 新 值或 旧 值 。 其 结 果 可 能 在 不 同 编 译 器 下 或 不 同 优 化 层 都 是 不 同 的 。 由 于 C 不 确 定 副 作 用 的 求 值 次 序 , 上 面 讨 论 的 求 值 方 法 都 是 正 确 的 , 也 可 以 实现 。
为 了 确 保 你 的 代 码 是 可 移 植 和 清 楚 的 , 避 免 使 用 其 副 作 用 依 赖 于 特 殊 求值 次 序 的 语 句 。
顺 序 点
连 贯 的 “ 顺 序 点 ” 之 间 , 一 个 对 象 的 值 仅 能 被 一 个 表 达 式 改 变 一 次 。 C
语 言 定 义 如 下 顺 序 点 :
-
逻 辑 AND 运 算 符 (&&) 的 左 操 作 数 。 逻 辑 AND 运 算 符 的 左 操 作 数 在 继续 之 前 完 成 求 值 和 完 成 所 有 的 副 作 用 。如 果 该 左 操 作 数 求 值 为 假 (0), 不 对 其 它 操 作 数 求 值 。
-
逻 辑 OR 运 算 符 (||) 的 左 操 作 数 。 逻 辑 OR 运 算 符 的 左 操 作 数 在 继 续之 前 完 成 求 值 和 完 成 所 有 的 副 作 用 。如 果 该 左 操 作 数 求 值 为 真 ( 非 0) , 不 对 其 它 操 作 数 求 值 。
-
逗 号 运 算 符 的 左 操 作 数 。 逗 号 运 算 符 的 左 操 作 数 在 继 续 之 前 完 成 求值 和 完 成 所 有 的 副 作 用 。 逗 号 运 算 符 的 两 个 操 作 数 总 是 求 值 。 注 意在 一 个 函 数 调 用 中 的 逗 号 运 算 符 不 保 证 求 值 的 次 序 。
-
函 数 调 用 运 算 符 。 在 进 入 一 个 函 数 之 前 对 该 函 数 的 所 有 参 量 求 值 和完 成 所 有 副 作 用 , 在 参 量 中 不 指 定 求 值 的 次 序 。
-
条 件 运 算 符 的 第 一 个 操 作 数 。 在 继 续 之 前 完 成 该 条 件 运 算 符 的 第 一个 操 作 数 的 求 值 并 完 成 所 有 的 副 作 用 。
-
一 个 完 整 初 始 化 表 达 式 结 束 ( 也 就 是 , 一 个 不 是 另 一 个 表 达 式 部 分 的表 达 式 , 例 如 , 在 一 个 说 明 语 句 中 一 个 初 始 化 的 结 果 ) 。
-
一 个 表 达 式 语 句 中 的 表 达 式 。 表 达 式 语 句 由 一 个 任 选 表 达 式 后 跟 一个 分 号 (;) 。 该 表 达 式 为 了 副 作 用 而 求 值 , 并 紧 跟 这 个 求 值 求 一 个 顺序 点 。
-
在 一 个 选 择 (if 或 switch) 语 句 中 的 控 制 表 达 式 。 在 依 赖 于 该 选 择的 代 码 执 行 之 前 完 成 该 表 达 式 的 求 值 , 并 完 成 所 有 的 副 作 用 。
-
一 个 while 或 do 语 句 的 控 制 表 达 式 。 在 while 或 do 循 环 的 下 一 次迭 代 中 的 任 何 语 句 执 行 之 前 完 成 该 表 达 式 的 求 值 , 并 完 成 所 有 的 副作 用 。
-
一 个 for 语 句 的 所 有 三 个 表 达 式 。 在 for 循 环 的 下 一 次 迭 代 中 的 任何 语 句 执 行 之 前 完 成 该 表 达 式 的 求 值 , 并 完 成 所 有 的 副 作 用 。
-
一 个 return 语 句 中 的 表 达 式 。 在 控 制 返 回 到 调 用 函 数 之 前 完 成 该表 达 式 的 求 值 , 并 完 成 所 有 的 副 作 用 。
运 算 符
有 三 种 类 型 的 运 算 符 。 单 目 表 达 式 由 一 个 单 目 运 算 符 加 到 一 个 操 作 数 组成 ,或 者 sizeof 关 键 字 跟 一 个 表 达 式 , 该 表 达 式 可 以 是 一 个 变 量 的 名 称 或一 个 造 型 表 达 式 。 如 果 该 表 达 式 是 一 个 造 型 表 达 式 , 它 必 须 包 括 在 圆 括号 中 。 一 个 双 目 表 达 式 由 两 个 操 作 数 加 上 连 接 的 双 目 运 算 符 组 成 。 一 个三 目 表 达 式 由 三 个 操 作 数 加 上 连 接 的 条 件 表 达 式 运 算 符 组 成 。
C 中 包 括 如 下 单 目 运 算 符 :
符号 名称
- ~ ! 取反和取非运算符
* & 间接访问和取地址运算符
sizeof 尺寸运算符
+ 单目加法运算符
++ -- 单目增 1 和减 1 运算符
双 目 运 算 符 从 左 向 右 结 合 。 C 提 供 如 下 双 目 运 算 符 :
符号 名称
* / % 乘 法 运 算 符
+ - 加 法 运 算 符
<< >> 移 位 运 算 符
<> <= >= == != 关 系 运 算 符& | ^ 按 位 运 算 符
&& || 逻 辑 运 算 符
, 顺序求值运算符
条 件 表 达 式 运 算 符 比 双 目 表 达 式 具 有 较 低 的 优 先 级 , 且 在 右 结 合 上 不 同 于 它 们 。带 运 算 符 的 表 达 式 也 包 括 赋 值 表 达 式 , 它 使 用 单 目 或 双 目 赋 值 运 算 符 。 单 目 赋 值运 算 符 是 增 1(++) 和 减 1(--) 运 算 符 ; 双 目 赋 值 运 算 符 是 简 单 赋 值 运 算 符 (=) 和 复合 赋 值 运 算 符 。
每 个 复 合 赋 值 运 算 符 是 另 外 的 双 目 运 算 符 与 简 单 赋 值 运 算 符 的 组 合 。
优 先 级 和 求 值 次 序
C 运 算 符 的 优 先 级 和 结 合 律 影 响 表 达 式 中 操 作 数 的 组 合 和 求 值 。 一 个 运 算 符 的优 先 级 仅 在 出 现 更 高 或 更 低 优 先 级 的 另 外 运 算 符 时 才 有 意 义 。 具 有 高 优 先 级 运算 符 的 表 达 式 首 先 求 值 。 优 先 级 也 可 以 通 过 词 “ 绑 定 ” (binding) 来 描 述 。 具 有更 高 优 先 级 的 运 算 符 被 说 成 具 有 更 紧 密 的 联 结 。
表 4.1 总 结 了 C 运 算 符 的 优 先 级 和 结 合 律 ( 运 算 符 求 值 的 次 序 ), 以 优 先 级 从 高 到低 列 出 。 而 几 个 运 算 符 只 能 一 起 出 现 , 它 们 具 有 相 等 的 优 先 级 并 根 据 它 们 的 结 合律 进 行 求 值 。 该 表 中 的 运 算 符 在 以 “ 后 缀 运 算 符 ” 开 头 的 小 节 中 。 本 节 的 余 下部 分 给 出 了 优 先 级 和 结 合 律 一 般 的 信 息 。
表 4.1 符号 1 |
C |
运 算 符 的 优 先 级 和 结 合 律 操作类型 |
结合律 |
---|---|---|---|
[] () . -> 后缀 ++ 和后缀 -- |
表达式 |
从左向右 |
|
前缀 ++ 和前缀 -- sizeof & + _ |
单目 |
从右向左 |
|
~ ! |
|||
类型造型 |
单目 |
从右向左 |
|
* / % |
乘法 |
从左向右 |
|
+ - |
加法 |
从左向右 |
|
<< >> |
位移 |
从左向右 |
|
<> <= >= |
关系 |
从左向右 |
|
== != |
相等 |
从左向右 |
|
& |
按位 AND |
从左向右 |
|
^ |
按位异或 |
从左向右 |
|
| |
按位 OR |
从左向右 |
|
&& |
逻辑 AND |
从左向右 |
|
|| |
逻辑 OR |
从左向右 |
|
? : |
条件表达式 |
从右向左 |
|
= *= /= %= |
简 单 和 复 合 2 |
赋 值 |
从右向左 |
+= -= <<= >>= |
|||
&= ^= |= |
续 表
, 顺序求值 从左向右
- 运 算 符 以 优 先 级 递 降 次 序 列 出 。 如 果 同 一 行 或 同 一 组 中 有 几 个 运 算符 出 现 , 它 们 具 有 相 同 的 优 先 级 。
- .所 有 简 单 和 复 合 赋 值 运 算 符 具 有 相 同 的 优 先 级 。
一 个 表 达 式 可 以 包 含 几 个 具 有 相 同 优 先 级 的 运 算 符 。 当 在 一 个 表 达 式 的同 一 层 中 出 现 几 个 这 样 的 运 算 符 时 , 根 据 这 些 运 算 符 的 结 合 律 从 右 向 左或 从 左 向 右 进 行 求 值 。 求 值 的 方 向 不 影 响 这 样 的 表 达 式 的 结 果 , 该 表 达式 在 同 层 中 可 以 包 含 多 个 乘 法 (*)、 加 法 (+) 或 双 目 按 位 (&|^) 运 算 符 。 优先 级 的 次 序 不 是 由 语 言 定 义 的 。 编 译 器 如 果 能 够 保 证 一 致 的 结 果 , 可 以以 任 意 次 序 对 表 达 式 求 值 。
只 有 顺 序 求 值 (,)、 逻 辑 AND(&& )、 逻 辑 OR(||) 、 条 件 表 达 式 (?:) 和 函 数
调 用 运 算 符 设 立 顺 序 点 , 因 此 保 证 这 些 运 算 符 的 特 殊 求 值 次 序 。 函 数 调用 运 算 符 是 该 函 数 标 识 符 之 后 的 一 组 圆 括 号 。 顺 序 求 值 运 算 符 (,) 保 证 从左 向 右 对 它 的 运 算 符 求 值 ( 注 意 , 在 一 个 函 数 调 用 中 逗 号 运 算 符 号 不 同于 顺 序 求 值 运 算 符 , 不 提 供 任 何 这 样 的 保 证 )。 有 关 更 多 信 息 , 参 见 本 章 前面 的 “ 顺 序 点 ”。
逻 辑 运 算 符 也 保 证 它 们 的 运 算 符 从 左 向 右 求 值 , 但 它 们 求 值 需 要 确 定 该表 达 式 结 果 的 最 少 的 运 算 符 个 数 。 这 称 之 为 “ 短 路 ” 求 值 。 因 些 , 该 表达 式 的 一 些 运 算 符 可 能 不 求 值 ,例 如 ,在 表 达 式 中 :
x && y++
只 有 x 为 真 ( 非 0), 第 二 个 运 算 符 y++ 才 被 求 值 ,因 此 ,如 果 x 为假 (0),则 y
不 增 1 。例 子
下 表 说 明 一 个 编 译 器 如 何 自 动 绑 定 几 个 基 本 表 达 式 。
表达式 自动联结
a&b||c (a&b)||c
a=b||c a=(b||c)
q&&r||s-- (q&&r)||s--
在 第 一 个 表 达 式 中 , 按位 AND 运 算 符 的 优 先 级 比 逻 辑 OR 运 算 符 (||) 的 优先 级 高 , 因此 ,a&b 形 成 了 逻 辑 OR 运 算 的 第 一 个 操 作 数 。
在 第 二 个 表 达 式 中 , 逻 辑 OR 运 算 符 (||) 比 简 单 赋 值 运 算 符 (= )有 更 高 的 优先 级 , 因 此 b||c 在 赋 值 中 作 为 右 边 运 算 符 进 行 组 合 。 注 意 赋 给 a 的 值 是 0 或 1 。
第 三 个 表 达 式 说 明 一 个 正 确 地 组 成 的 表 达 式 可 能 产 生 一 个 不 可 预 料 的 结果 。 逻 辑 AND 运 算 符 (&& )比 逻 辑 OR 运 算 符 (||) 的 优 先 级 高 ,因 此 ,q&&r 结 合 成 一 个 操 作 数 。 由 于 逻 辑 运 算 符 保 证 从 左 向 右 求 值 ,q&&r 在 s -- 之前 被 求 值 。 如 果 q&&r 求 值 为 非 0 值 ,s -- 不 再 求 值 ,s 不 减 1 。
如 果 s 不 减 1 ,可 能 导 致 程 序 出 问 题 ,s-- 应 在 表 达 式 中 作 为 第 一 个 操 作 数出 现 , 或 者 s 在 一 个 分 开 的 操 作 中 减 1 。
下 面 的 表 达 式 是 非 法 的 ,在 编 译 时 产 生 一 个 诊 断 消 息 :
非法表达式 缺省组合
p==0?p+=1:p+=2 (p==0?p+=1:p)+=2
在 这 个 表 达 式 中 , 相 等 运 算 符 (== )有 最 高 的 优 先 级 ,因 此 p==0 组 合 成 一 个
操 作 数 。 条 件 表 达 式 运 算 符 (?:) 有 次 高 的 优 先 级 , 它 的 第 一 个 操 作 数 是p==0, 第 二 个 操 作 数 是 p+=1 。 但 该 条 件 表 达 式 运 算 符 的 最 后 操 作 数 被 认为 是 p 而 不 是 p+=2 ,这 是 由 于 p 与 该 条 件 表 达 式 运 算 符 的 结 合 比 与 该 复合 赋 值 运 算 符 的 绑 定 更 紧 密 。 因 为 +=2 没 有 左 边 运 算 符 , 出 现 一 个 语 法错 误 。
你 可 以 使 用 圆 括 号 防 止 这 种 错 误 出 现 并 产 生 更 可 读 的 代 码 。 例 如 , 你 可以 使 用 如 下 圆 括 号 以 改 正 前 面 的 例 子 并 使 之 更 清 楚 : (p==0)?(p+=1):(p+=2)
常 用 的 算 术 转 换
大 多 数 C 运 算 符 执 行 类 型 转 换 把 一 个 表 达 式 的 操 作 数 转 换 成 共 同 的 类型 或 扩 充 短 的 值 为 机 器 操 作 中 使 用 的 整 数 尺 寸 。 C 运 算 符 执 行 的 转 换 依赖 于 特 定 运 算 符 和 操 作 数 的 类 型 或 操 作 数 。 但 很 多 运 算 符 在 整 数 和 浮 点类 型 的 操 作 数 上 执 行 相 似 的 转 换 , 这 些 转 换 就 是 众 所 周 知 的 “ 算 术 转换 ”。 一 个 操 作 数 值 转 换 成 一 个 兼 容 的 类 型 使 其 值 不 发 生 改 变 。
下 面 总 结 的 算 术 转 换 称 为 “ 常 用 的 算 术 转 换 ”。 这 些 步 骤 仅 应 用 于 算 术类 型 的 双 目 运 算 符 以 及 两 个 操 作 数 不 是 相 同 类 型 的 情 况 。 其 目 的 是 产 生一 个 公 共 的 类 型 , 它 也 是 最 后 结 果 的 类 型 。 为 了 确 定 实 际 发 生 的 转 换 , 编译 器 把 如 下 算 法 应 用 于 表 达 式 中 的 双 目 操 作 。 下 面 步 骤 的 次 序 不 是 按 优先 级 给 出 的 :
- 如 果 操 作 数 之 一 类 型 为 long double, 则 其 它 操 作 数 转 换 成 long double
类 型 。
- 如 果 上 述 条 件 不 满 足 , 且 操 作 数 之 一 类 型 为 double ,则
其 它 操 作 数 转 换成 double 类 型 。
-
.如 果 上 述 两 个 条 件 不 满 足 ,且 操 作 数 之 一 为 float 类 型
, 则 其 它 操 作 数 转换 成 float 类 型 。
-
.如 果 上 述 三 个 条 件 都 不 满 足 ( 没 有 操 作 数 为 浮 点 类 型
), 那 么 在 操 作 数 上执 行 如 下 整 数 转 换 :
-
如 果 操 作 数 之 一 为 unsigned long 类 型 , 则 其 它 操 作 数 转 换 成unsigned long 类 型 。
-
如 果 上 述 条 件 不 满 足 , 且 操 作 数 之 一 为 long 类 型 , 其 它 为 unsigned int 类 型 , 则 操 作 数 都 转 换 成 unsigned long 类 型 。
-
如 果 上 述 两 个 条 件 都 不 满 足 , 且 操 作 数 之 一 为 long 类 型 , 则 其 它 操作 数 转 换 成 long 类 型 。
-
如 果 上 述 三 个 条 件 都 不 满 足 , 且 操 作 数 之 一 为 unsigned int, 则 其 它操 作 数 转 换 成 unsigned int 类 型 。
-
如 果 上 述 条 件 都 不 满 足 , 则 操 作 数 都 转 换 成 int 类 型
。以 下 例 子 说 明 了 这 些 转 换 规 则 :
float fVal; double dVal; inti Val;
unsigned long ulVal;
dVal = iVal * ulVal; /*iVal 使用步骤 4 转 换 为 unsigned long
* 乘法的结果转换成 double */
dVal = ulVal + fVal; /*ulVal 使用步骤 3 转换为 float
* 加法的结果转换成 double */
后 缀 运 算 符
后 缀 运 算 符 在 表 达 式 值 中 具 有 最 高 的 优 先 级 ( 最 紧 密 的 绑 定 )。
语法
后缀表达式 :
基本表达式
后缀表达式 [ 表达式 ]
后缀表达式 [ 参量表达式表 opt]
后缀表达式 .标 识 符后缀表达式 -> 标识符后缀表达式 ++
后缀表达式 --
在 这 个 优 先 级 层 中 的 运 算 符 有 数 组 下 标 、 函 数 调 用 、 结 构 和 联 合 成 员 以及 后 缀 增 1 和 后 缀 减 1 运 算 符 。
- 维 数 组
一 个 后 缀 表 达 式 后 跟 一 个 方 括 号 ([]) 中 的 表 达 式 是 一 个 数 组 对 象 的 一 个元 素 的 下 标 表 示 。 一 个 下 标 表 达 式 表 示 这 样 地 址 的 值 , 其 地 址 是 该 后 缀表 达 式 加 上 表 达 式 中 指 定 值 的 位 置 ,表 示 为 :
后 缀 表 达 式 [ 表 达 式 ]
通 常 , 由 后 缀 表 达 式 表 示 的 值 是 一 个 指 针 值 , 例 如 一 个 数 组 标 识 符 和 一 个表 达 式 是 一 个 整 数 值 。 但 所 有 语 法 上 需 要 的 是 一 个 为 指 针 类 型 的 表 达 式 , 另 一 个 为 整 数 类 型 。 因 此 , 整 数 值 可 以 在 后 缀 表 达 式 位 置 , 指 针 值 可 以 在方 括 号 的 表 达 式 中 或 “ 下 标 ” 位 置 。 例 如 ,如 下 代 码 是 合 法 的 :
int sum *ptr,a[10]; int main
{
ptr=a; sum=4[ptr];
}
下 标 表 达 式 通 常 用 于 指 向 数 组 元 素 , 但 你 可 以 将 下 标 应 用 于 任 何 指 针 。无 论 值 的 次 序 , 表 达 式 必 须 包 括 在 方 括 号 ([]) 中 。
下 标 表 达 式 通 过 把 整 数 值 加 上 指 针 值 , 然 后 在 结 果 上 应 用 间 接 访 问 运 算符 (*) 求 值 ( 有 关 间 接 访 问 运 算 符 的 讨 论 ,参 见 本 章 后 面 的 “ 间 接 访 问 和 取地 址 运 算 符 ” )。 实 际 上 , 如 下 四 个 表 达 式 是 相 等 的 , 假设 a 是 一 个 指 针 ,b 是 一 个 整 数 :
a[b]
*(a+b)
*(b+a)
b[a]
根 据 加 法 运 算 符 的 转 换 规 则 ( 在 “ 加 法 运 算 符 ” 中 给 出 ),该 整 数 值 通 过 将它 乘 以 指 针 地 址 类 型 的 长 度 来 将 其 转 换 成 一 个 地 址 偏 移 量 。
假 如 , 假 设 标 识 符 line 指 向 一 个 int 类 型 的 数 组 , 如 下 过 程 用 于 计 算 下 标 表达 式 ling[i] 的 值 :
- 整 数 值 I 被 一 个 int 项 长 度 确 定 的 字 节 个 数 相 乘 。 i 的 转 换 值 表 示 i 个
int 位 置 。
- 这 个 转 换 的 值 加 上 最 初 指 针 值 (line )产 生 一 个 地 址 , 它 是 距 离 line 偏 移
i 个 int 的 位 置 。
- 将 间 接 访 问 运 算 符 应 用 于 该 新 地 址 。其 结 果 是 该 位 置
数 组 元 素 的 值 ( 直观 地 为 line[i])。
下 标 表 达 式 line[0]表 示 line 的 第 一 个 元 素 的 值 ,由 于 它 偏 移 line 所 表 示的 地 址 为 0 。 类 似 地 , 一 个 表 达 式 例 如 line[5]指 的 是 偏 移 line 为 5 个 位 置的 元 素 或 该 数 组 的 第 6 个 元 素 。
多 维 数 组
- 个 下 标 表 达 式 也 可 以 有 多 个 下 标 ,如 下 :
expression1[expression2][expression3]...
下 标 表 达 式 从 左 向 右 结 合 。 最 左 下 标 表 达 式 expression1[expression2] 首先 求 值 。 其 地 址 加 上 expression1 和 expression2 构 成 一 个 指 针 表 达式 ;expression3 加 上 这 个 指 针 表 达 式 构 成 一 个 新 的 指 针 表 达 式 , 如 此 等 等直 到 最 后 下 标 表 达 式 已 加 上 了 。 在 最 后 下 标 表 达 式 求 值 之 后 应 用 间 接 访问 运 算 符 (*), 除 非 最 后 的 指 针 值 是 一 个 数 组 类 型 的 地 址 ( 参 见 下 面 的 例子 )。
具 有 多 个 下 标 的 表 达 式 指 的 是 “ 多 维 数 组 ”。 一 个 多 维 数 组 是 一 个 其 元
素 是 数 组 的 数 组 。 例 如 ,一 个 三 维 数 组 的 第 一 个 元 素 是 一 个 两 维 数 组 。
例 子
对 于 如 下 例 子 中 , 一 个 命 名 为 prop 的 数 组 用 三 个 元 素 说 明 , 每 个 是 一 个 int
类 型 的 4 × 6 数 组 。
int prop[3][4][6];
int i,*ip,(*ipp)[6];
如 下 引 用 prop 数 组 :
i=prop[0][0][1];
上 面 例 子 说 明 了 如 何 引 用 prop 的 第 2 个 int 元 素 。 数 组 以 行 存 储 ,因 此最 后 的 下 标 最 快 地 变 化 ;表 达 式 prop[0][0][2] 指 的 是 该 数 组 的 下 一 个 ( 第 3 个 )元 素 , 等 等 。
i=prop[2][1][3];
这个语句更加复杂地引用 prop 的单个元素。该表达式求值如下 :
- 第 1 个 下 标 为 2 ,由 4 × 6 的 int 数 组 的 尺 寸 相 乘 ,再 加 上 prop 的 指 针 值 ,
其 结 果 指 向 prop 的 第 3 个 4 × 6 数 组 。
-
第 2 个 下 标 为 1 ,由 6 个 元 素 int 数 组 的 尺 寸 相 乘 , 再 加
上 prop[5] 表 示的 地 址 。
-
该 6 元 素 数 组 的 每 一 个 元 素 是 一 个 int 值 , 因 此 , 最 后
下 标 3, 在 加 到prop[2][1] 之 前 由 一 个 int 的 尺 寸 相 乘 。 结 果 指 针 是 该 6 元 素 数 组 的 第 4 个 元 素 。
-
将 间 接 访 问 运 算 符 应 用 到 该 指 针 值 。 其 结 果 是 该 地 址
处 的 int 元 素 。如 下 两 个 例 子 说 明 了 不 应 用 间 接 访 问 运 算 符 的 情 况 :
ip=prop[2][1];
ipp=prop[2];
在 上 述 语 句 的 第 一 个 语 句 中 , 表 达 式 prop[2][1] 是 该 三 维 数 组 prop 的 有 效引 用 。 它 指 的 是 第 一 个 6 元 素 数 组 ( 上 述 说 明 的 )。 由 于 该 指 针 值 是 一 个数 组 的 地 址 ,不 能 应 用 间 接 访 问 运 算 符 。
类 似 地 , 在 第 二 个 语 句 ipp=prop[2] 中 , 表 达 式 prop[2] 的 结 果 是 一 个 二 维 数组 的 地 址 的 指 针 值 。
函 数 调 用
一 个 “ 函 数 调 用 ” 是 一 个 包 含 被 调 用 函 数 的 名 称 或 函 数 指 针 值 或 者 传 送给 该 函 数 的 任 选 参 量 的 表 达 式 。
语法
后缀表达式 :
后缀表达式 ( 参量表达式表 opt)
参量表达式表 :
赋值表达式
参量表达式表 ,赋值表达式
后 缀 表 达 式 必 须 计 算 一 个 函 数 地 址 ( 例 如 , 一 个 函 数 标 识 符 或 一 个 函 数 指针 的 值 ), 参 量 表 达 式 表 是 一 个 其 值 (“ 参 量 ”) 传 送 给 该 函 数 的 表 达 式 表 ( 用逗 号 分 隔 表 达 式 )。 参 量 表 达 式 表 参 量 可 以 为 空 。
- 个 函 数 调 用 表 达 式 具 有 该 函 数 返 回 的 值 和 类 型 , 一 个 函 数 不 能 返 回 一个 数 组 类 型 的 对 象 , 如 果 该 函 数 的 返 回 类 型 为 void( 也 就 是 ,该 函 数 说 明 为
没 有 返 回 值 ), 则 该 函 数 调 用 表 达 式 也 有 void 类 型 ( 有 关 更 多 信 息 ,参 见 第
6 章 “ 函 数 ” 中 的 “ 函 数 调 用 ” )。
结 构 和 联 合 成 员
- 个 “ 成 员 选 择 表 达 式 ” 指 的 是 结 构 和 联 合 的 成 员 , 这 样 的 一 个 表 达 式具 有 选 择 的 成 员 的 值 和 类 型 。
语 法
后 缀 表 达 式 .标 识 符后 缀 表 达 式 -> 标 识 符
这 个 表 描 述 了 成 员 选 择 表 达 式 的 两 种 格 式 :
-
在 第 一 种 格 式 中 ,后 缀 表 达 式 表 示 一 个 struct 或 union 类 型 的 值 ,标 识符 命 名 该 指 定 结 构 或 联 合 的 一 个 成 员 。 该 操 作 的 值 就 是 该 标 识 符 的 值 , 如 果 后 缀 表 达 式 是 一 个 l 值 ,则 该 操 作 的 值 也 是 一 个 l 值 。 有 关 更 多 信 息 , 参 见 本 章 前 面 的 “ L 值和 R 值 表 达 式 ”。
-
在 第 二 种 格 式 中 , 后 缀 表 达 式 表 示 一 个 结 构 或 联 合 的 一 个 指 针 , 标 识 符命 名 该 指 定 结 构 或 数 组 的 一 个 成 员 。 其 值 是 该 标 识 符 的 值 , 且 是 一 个 l 值 。
成 员 选 择 表 达 式 的 两 种 格 式 具 有 类 似 的 作 用 。 事 实 上 , 涉 及 成 员 选 择 运算 符 (-> )的 表 达 式 是 这 样 的 表 达 式 的 速 记 版 本 , 这 个 表 达 式 使 用 句 点 且 该句 点 之 前 的 表 达 式 由 作 用 于 一 个 指 针 值 的 间 接 访 问 运 算 符 组 成 。 因 此 : 表 达 式 -> 标 识 符
等 价 于 :
(* 表达式 ) .标识符
这 里 表 达 式 是 一 个 指 针 值 。
例 子
如 下 例 子 指 的 是 这 种 结 构 说 明 ,有 关 在 这 些 例 子 中 使 用 间 接 访 问 运 算 符 (*
的 信 息 , 参 见 本 章 后 面 的 “ 间 接 访 问 和 取 地 址 运 算 符 ”。
struct pair
{
int a; int b;
struct pair *sp;
} item,list[10];
item 的 一 个 成 员 选 择 表 达 式 如 下 :
item.sp=&item
在 上 述 例 子 中 , 将 item 结 构 的 地 址 赋 给 该 结 构 的 sp 成 员 。 这 样 item 包含 自 身 的 一 个 指 针 。
(item.sp)->a = 24;
在 这 个 例 子 中 , 指 针 表 达 式 item.sp 与 成 员 选 择 运 算 符 (->) 一 起 使 用 把 一个 值 赋 给 a:
list[8].b = 12;
这 个 语 句 说 明 如 何 从 一 个 结 构 数 组 选 择 单 个 结 构 成 员 。
后 缀 增 1 和 减 1 运 算 符
后 缀 增 1 和 减 1 运 算 符 的 操 作 数 是 可 修 改 的 l 值 的 标 量 类 型 。语 法
后缀表达式 :
后缀表达式 ++
后缀表达式 --
后 缀 增 1 或 减 1 操 作 的 结 果 是 该 操 作 数 的 值 。 在 获 得 结 果 后 , 该 操 作 数增 1( 或 减 1)。 如 下 代 码 说 明 该 后 缀 增 1 运 算 符 。
if (var++>0)
*p++=*q++;
本 例 中 , 变量 var 是 与 0 进 行 比 较 , 如果 var 在 增 1 之 间 是 正 数 , 则 执 行 下一 个 语 句 。 首 先 , 由 q 所 指 对 象 的 值 赋 给 由 q 所 指 的 对 象 , 然后 ,q 和 p 都增 1 。
单 目 运 算 符
单 目 运 算 符 出 现 它 的 操 作 数 之 前 并 从 右 向 左 结 合 。
语法
单目表达式 :
后缀表达式
++ 单目表达式
-- 单目表达式
单目运算符 造型表达式sizeof 单 目 表 达 式 sizeof( 类型名称 )
单 目 运 算 符 :如 下 之 一
& * + - ~ !
前 缀 增 1 和 减 1 运 算 符
当 增 1 和减 1 运 算 符 出 现 在 操 作 数 之 间 时 , 单 目 运 算 符 (++ 和 --) 被 称 为“ 前 缀 ” 增 1 和 减 1 运 算 符 。
后 缀 增 1 和 减 1 的 优 先 级 比 前 缀 增 1 和 减 1 运 算 符 的 优 先 级 高 。 操 作 数必 须 是 整 数 、 浮 点 或 指 针 类 型 以 及 必 须 是 一 个 可 修 改 的 l 值 表 达 式 ( 一个 没 有 const 属 性 的 表 达 式 )。 其 结 果 是 一 个 l 值 。
当 运 算 符 出 现 在 操 作 数 之 前 时 , 该 操 作 被 增 1 或 减 1, 其 新 值 是 该 表 达 式的 结 果 。
-
个 整 数 或 浮 点 类 型 的 操 作 数 增 大 或 减 小 整 数 值 1, 其 结 果 的 类 型 与 操 作数 类 型 相 同 。
-
个 指 针 类 型 的 操 作 数 增 大 或 减 小 它 地 址 所 指 对 象 的 尺 寸 , 一 个 增 1 的指 针 指 向 下 一 个 对 象 ,一 个 减 1 的 指 针 指 向 前 一 个 对 象 。
例 子
这 个 例 子 说 明 单 目 前 缀 减 1 运 算 符 :
if (line [--i]!= ′ \n ′ ) return;
在 这 个 例 子 中 , 变 量 i 在 作 为 line 的 下 标 之 前 减 1 。
间 接 访 问 和 取 地 址 运 算 符
间 接 访 问 运 算 符 (*) 通 过 一 个 指 针 间 接 访 问 一 个 值 。 该 操 作 值 必 须 是 一个 值 。 该 操 作 数 必 须 是 一 个 指 针 值 。 其 操 作 结 果 是 该 操 作 数 所 指 的 值 , 也 就 是 该 操 作 数 所 指 地 址 处 的 值 。 其 结 果 类 型 是 该 操 作 数 所 指 地 址 的 类型 。
如 果 操 作 数 指 向 一 个 函 数 , 其 结 果 是 一 个 函 数 指 示 符 , 如 果 它 指 向 一 个 存储 位 置 , 其 结 果 是 一 个 l 值 指 示 该 存 储 位 置 。
如 果 该 指 针 值 是 无 效 的 , 其 结 果 是 不 确 定 的 。 如 下 表 包 括 无 效 指 针 值 的一 些 最 普 遍 的 条 件 :
-
该 指 针 是 一 个 空 指 针 。
-
该 指 针 指 出 一 个 在 引 用 时 不 可 见 的 局 部 项 的 地 址 。
-
该 指 针 指 出 一 个 不 适 合 赋 给 该 对 象 所 指 类 型 的 地 址 。
-
该 指 针 指 出 一 个 执 行 程 序 不 能 使 用 的 地 址 。
取 地 址 运 算 符 (& ) 给 出 它 的 操 作 数 的 地 址 。 取 地 址 运 算 符 的 操 作 数 可 以是 一 个 函 数 指 示 符 或 一 个 l 值 ,该 l 值 指 示 一 个 不 是 位 域 的 对 象 , 且 没 有 用register 存 储 类 指 示 符 说 明 。
取 地 址 运 算 符 的 结 果 是 该 操 作 数 的 指 针 , 该 指 针 所 指 地 址 的 类 型 是 操 作数 的 类 型 。
取 地 址 运 算 符 只 能 应 用 于 在 文 件 范 围 层 说 明 的 基 本 类 型 、 结 构 或 联 合 类型 或 者 下 标 数 组 的 引 用 。 在 这 些 表 达 式 中 , 在 该 地 址 表 达 式 中 可 以 加 上
或 减 去 一 个 不 包 括 取 地 址 运 算 符 的 常 量 表 达 式 。例 子
下 面 的 例 子 使 用 三 个 说 明 :
int *pa,x; int a[20]; double d;
下 面 的 语 句 使 用 取 地 址 运 算 符 :
pa=&a[5];
该 取 地 址 运 算 符 (& )取 数 组 a 的 第 6 个 元 素 的 地 址 , 把 结 果 存 储 在 指 针 变量 pa 中。
x=*pa;
在 这 个 例 子 中 使 用 间 接 访 问 运 算 符 (& )访 问 存 储 在 pa 地 址 处 的 int 值 , 把该 值 赋 给 整 数 变 量 x 。
if (x == *&x)
printf("True\n");
这 个 例 子 打 印 单 词 True ,从 而 证 实 把 间 接 访 问 运 算 符 应 用 于 x 的 地 址 的结 果 与 x 是 相 同 的 。
int roundup(void); /* 函数说明 */
int *proundup=roundup; int *pround=&roundup;
-
旦 说 明 了 函 数 roundup, 该 roundup 的 两 个 指 针 也 说 明 和 初 始 化 了 。 第
-
个 指 针 proundup 仅 使 用 该 函 数 的 名 称 初 始 化 ,而 第 二 个
指 针 pround 在
初 始 化 中 使 用 取 地 址 运 算 符 。 这 两 种 初 始 化 是 相 同 的 。
单 目 算 术 运 算 符
在 下 表 中 讨 论 C 单 目 加 、 算 术 取 反 、 按 位 取 反 和 逻 辑 非 运 算 符 。
运 算 说明
符
+ 单 目 加 运 算 符 位 于 圆 括 号 中 一 个 表 达 式 的 前 面 强 制 组 合 括 起 的 操作 。 它 用 在 涉 及 多 个 结 合 或 交 换 双 目 运 算 符 的 表 达 式 中 。 该 操 作 数必 须 是 算 术 类 型 。 其 结 果 是 操 作 数 的 值 。 一 个 整 数 操 作 数 要 进 行 整数提升 , 结果的类型是提升的操作数的类型。
- 算 术 取 反 运 算 符 产 生 该 操 作 数 的 取 反 值 (2 的补码 ) 。 该 操 作 数 必 须是整数或浮点值。这个运算符执行常用的算术转换。
~ 按位取反 ( 或按位 NOT) 运 算 符 产 生 其 操 作 数 的 按 位 取 反 。 该 操 作 数必 须 是 整 数 类 型 。 这 个 运 算 符 执 行 常 用 的 算 术 转 换 , 其 结 果 具 有 转换后的操作数的类型。
! 逻辑非 ( 逻辑 NOT) 运算符在操作数为真 ( 非 0) 时产生值 0, 在操作数为假 (0) 时产生值 1 。其结果具有 int 类型。该操作数必须是一个整数、浮点或指针值。
指 针 上 的 单 目 算 术 操 作 是 非 法 的 。
例 子
如 下 例 子 说 明 单 目 算 术 运 算 符 :
short x=987;
x=-x;
在 上 述 例 子 中 ,x 的 新 值 是 987 的 算 术 取 反 即 -987 。
unsigned short y=0xAAAA; y=~y;
在 这 个 例 子 中 ,y 的 新 值 是 无 符 号 值 0xAAAA 的 按 位 取 反 即 0x5555 。
if (!(x<y))
如 果 x 大 于 或 等 于 y, 该 表 达 式 的 结 果 是 1( 真 )。 如 果 x 小 于 y, 其 结 果 是
0( 假 )。
sizeof 运 算 符
sizeof 运 算 符 以 字 节 为 单 位 给 出 存 储 该 操 作 数 的 类 型 的 对 象 所 需 要 的 存储 数 目 。 这 个 运 算 符 允 许 你 在 程 序 中 避 免 指 定 依 赖 于 机 器 的 数 据 尺 寸 。语 法
sizeof 单 目 表 达 式
sizeof( 类 型 名 称 )
该 操 作 数 是 一 个 为 单 目 表 达 式 或 类 型 造 型 表 达 式 ( 也 就 是 , 一 个 类 型 指 示符 放 在 圆 括 号 中 ) 的 标 识 符 。 该 单 目 表 达 式 不 能 表 示 一 个 位 域 对 象 、 一个 不 完 整 类 型 或 一 个 函 数 指 示 符 。 其 结 果 是 一 个 无 符 号 整 数 参 量 。 标 准头 文 件 STDDEF.H 定 义 这 个 类 型 为 size _ t。
当 你 把 该 sizeof 运 算 符 应 用 到 一 个 数 组 标 识 符 时 , 其 结 果 是 整 个 数 组 的
尺 寸 而 不 是 该 数 组 标 识 符 表 示 的 指 针 的 尺 寸 。
当 你 把 该 sizeof 运 算 符 应 用 到 一 个 结 构 或 联 合 类 型 名 称 ,或 者 一 个 结 构
或 联 合 类 型 的 标 识 符 时 , 其 结 果 是 该 结 构 或 联 合 的 字 节 个 数 , 包 括 内 部 的和 尾 部 的 填 充 。 这 个 尺 寸 可 以 包 括 用 于 在 存 储 器 边 界 上 对 齐 结 构 或 联 合的 成 员 而 使 用 的 内 部 和 尾 部 填 充 。 因 此 , 其 结 果 可 能 不 对 应 于 所 有 成 员所 需 存 储 相 加 的 结 果 。
如 果 一 个 没 有 尺 寸 的 数 组 是 一 个 结 构 的 最 后 元 素 , 则 sizeof 运 算 符 返 回没 有 该 数 组 的 结 构 的 尺 寸 。
buffer=calloc(100,sizeof(int));
这 个 例 子 使 用 sizeof 运 算 符 传 送 一 个 int 的 尺 寸 , 它 在 不 同 的 机 器 中 可 能不 同 , 作 为 一 个 参 量 传 送 给 名 称 为 calloc 的 运 行 函 数 。 由 这 个 函 数 返 回的 值 存 储 在 buffer 中 。
static char *strings[] = { "this is string one", "this is string two", "this is string three",
};
const int string_no = (sizeof strings) / sizeof strings[0]);
在 这 个 例 子 中 ,strings 是 一 个 char 的 指 针 的 数 组 。 该 指 针 的 成 员 是 数 组中 的 元 素 个 数 , 但 不 是 指 定 的 。 使 用 sizeof 运 算 符 计 算 该 数 组 中 的 元 素个 数 容 易 确 定 指 针 个 数 。 const 整 数 值 string_no 初 始 化 为 这 个 数 。 因 为这 是 一 个 const 值 ,string_no 不 能 修 改 。
造 型 运 算 符
- 个 类 型 造 型 提 供 了 在 特 定 状 态 下 显 式 转 换 一 个 对 象 类 型 的 方 法 。语 法
造型表达式 :
单目表达式
(类 型 名 称 )造 型 表 达 式
在 类 型 造 型 强 制 转 换 之 后 , 编 译 器 处 理 造 型 表 达 式 为 类 型 名 称 所 指 的 类型 。 造 型 可 以 把 任 何 标 量 类 型 的 对 象 转 换 成 另 一 种 标 量 类 型 的 对 象 。 显式 类 型 造 型 也 遵 守 本 章 后 面 “ 赋 值 转 换 ” 中 的 讨 论 的 隐 含 转 换 规 则 。 造型 上 的 另 外 限 制 来 自 指 定 类 型 的 实 际 尺 寸 或 表 示 。 有 关 整 数 类 型 的 实 际尺 寸 的 信 息 ,参 见 第 3 章 “ 说 明 和 类 型 ” 中 的 “ 基 本 类 型 的 存 储 ”。 有 关类 型 造 型 的 更 多 信 息 ,参 见 本 章 后 面 的 “ 类 型 造 型 转 换 ”。
乘 法 运 算 符
乘 法 运 算 符 执 行 乘 法 (*)、 除 法 (/) 和 余 数 (% )操 作 。
语法
乘法表达式 :
造型表达式
乘法表达式 * 造型表达式乘法表达式 / 造型表达式乘法表达式 % 造型表达式
余 数 运 算 符 (% )的 操 作 数 必 须 是 整 数 。 乘 法 (*) 和 除 法 (/) 运 算 符 可 以 使 用整 数 或 浮 点 类 型 操 作 数 ,操 作 数 的 类 型 可 以 不 同 。
乘 法 运 算 符 对 操 作 数 执 行 常 用 的 算 术 转 换 , 其 结 果 的 类 型 是 转 换 后 操 作数 的 类 型 。
注 意 : 由 于 乘 法 运 算 符 执 行 的 转 换 不 提 供 上 溢 出 和 下 溢 出 条 件 , 如 果 一个 乘 法 运 算 的 结 果 不 能 以 转 换 后 的 操 作 数 的 类 型 表 示 , 则 可 能 丢 失 信息。
c 乘 法 运 算 符 的 描 述 如 下 :
运算符 说明
* 该乘法运算符导致它们两个操作数相乘
/ 该除法运算符导致第一个操作数被第二个操作数相除
如 果 两 个 整 数 相 除 且 结 果 不 是 一 个 整 数 , 则 根 据 如 下 规 则 截 除它 :
-
根据 ANSI C 标准 , 除 0 的结果是不确定的 ,C 编译器在编译时或运行时产生一个错误
-
如果两个操作数是正数或无符号数 , 其结果向 0 进行截除
-
如果有一个操作数为负数 , 该运算的结果是小于或等于代数 商 的 最 大 整 数 或 者 大 于 或 等 于 代 数 商 的 最 小 整 数 , 这被实现所定义 ( 参见下面的 Microsoft 特殊处小节 )
续 表
运算符 说明
% 余 数 运 算 符 的 结 果 是 第 一 个 操 作 数 除 以 第 二 个 操 作 数 所 得 的余数。当除法不精确时 , 其结果由如下规则确定:
-
如果右边操作数是 0, 其结果是不确定的
-
如果两个操作数都是正数或无符号数 , 其结果为正数
-
如 果 有 一 个 操 作 数 为 负 数 , 其 结 果 是 不 精 确 的 , 它 们 被 实现所定义 ( 参见下面 的 Microsoft 特殊处小节 )
Microsoft 特 殊 处 →
在 有 一 个 操 作 数 为 负 数 的 除 法 中 ,截 除 的 方 向 朝 向 0 。
如 果 使 用 余 数 运 算 符 的 除 法 中 有 一 个 操 作 数 为 负 数 , 其 结 果 与 被 除 数 ( 表达 式 中 的 第 一 个 操 作 数 ) 的 符 号 相 同 。
Microsoft 特 殊 处 结 束例 子
下 面 的 说 明 使 用 以 下 例 子 :
int i=10,j=3,n; double x=2.0,y;
这 个 语 句 使 用 乘 法 运 算 符 :
y=x*i;
在 这 种 情 况 下 ,x 乘 以 i 得 到 值 20.0 ,其 结 果 为 double 类 型 。
n=i/j;
在 这 个 例 子 中 ,10 被 3 相 除 , 结 果 朝 向 0 进 行 截 除 ,产 生 整 数 3 。
n=i% j;
这 个 语 句 赋 给 n 为 10 除 以 3 的 余 数 即 1 。
Microsoft 特 殊 处 →
余 数 的 符 号 与 被 除 数 的 符 号 相 同 ,例 如 :
50%-6=2
-50%6=-2
以 下 情 况 下 ,50 与 2 具 有 相 同 的 符 号 。
Microsoft 特 殊 处 结 束加 法 运 算 符
加 法 运 算 符 执 行 加 法 (+ )和 减 法 (-)
语法
加法表达式 :
乘法表达式
加法表达式 + 乘法表达式加法表达式 - 乘法表达式
注 意 : 虽 然 加 法 表 达 式 的 语 法 包 括 乘 法 表 达 式 , 这 并 不 表 示 一 定 需
要 使 用 乘 法 。 有 关 乘 法 表 达 式 、 造 型 表 达 式 和 单 目 表 达 式 , 参 见 本 书 后面 的 附 录 A “ C 语 言 语 法 总 结 ”。
操 作 数 可 以 是 整 数 或 浮 点 值 。 有 些 加 法 运 算 也 可 以 在 指 针 值 上 执 行 , 正如 每 个 运 算 符 的 讨 论 中 概 述 的 。
加 法 运 算 符 在 整 数 和 浮 点 操 作 数 上 执 行 常 用 的 算 术 转 换 。 其 结 果 的 类 型
是 转 换 后 操 作 数 的 类 型 。 由 于 加 法 运 算 符 执 行 的 转 换 不 提 供 上 溢 出 或 下溢 出 条 件 , 如 果 一 个 加 法 运 算 的 结 果 不 能 由 转 换 后 操 作 数 的 类 型 表 示 , 则可 能 丢 失 信 息 。
加 法 (+)
加 法 运 算 符 (+) 导 致 两 个 操 作 数 相 加 。 两 个 操 作 数 可 以 是 整 数 或 浮 点 类型 ,或 者 一 个 操 作 数 且 另 一 个 操 作 数 是 一 个 整 数 。
当 把 一 个 整 数 加 上 一 个 指 针 时 , 整 数 值 (i) 通 过 将 它 乘 以 该 指 针 所 指 值 的尺 寸 来 转 换 。 在 转 换 之 后 ,整 数 值 表 示 i 存 储 器 位 置 ,而 每 个 位 置 都 有 其指 针 类 型 指 定 的 长 度 。 不 转 换 的 整 数 值 加 到 该 指 针 值 时 , 其 结 果 是 一 个新 的 指 针 值 以 表 示 距 离 最 初 地 址 i 个 位 置 的 地 址 。 该 新 的 指 针 值 指 向 与最 初 指 针 值 相 同 类 型 的 值 , 因 此 与 数 组 指 标 相 同 ( 参 见 本 章 前 面 的 “ 一 维数 组 ” 和 “ 多 维 数 组 ” ) 。 如 果 和 的 指 针 指 向 超 过 了 该 数 组 范 围 , 除 了 在超 过 最 高 端 的 第 一 个 位 置 外 , 其 结 果 是 不 确 定 的 。 有 关 更 多 信 息 参 见 本章 后 面 的 “ 指 针 算 术 ”。
减 法 (-)
减 法 运 算 符 (-) 从 第 一 个 操 作 数 减 去 第 二 个 操 作 数 。 两 个 操 作 数 可 以 是 整数 或 浮 点 类 型 , 或 者 一 个 操 作 数 可 以 是 一 个 指 针 且 另 一 个 操 作 数 是 一 个整 数 。
当 两 个 指 针 相 减 时 , 其 差 通 过 除 以 该 指 针 所 指 类 型 的 值 的 尺 寸 来 转 换 成一 个 有 符 号 整 数 值 。 该 整 数 值 的 尺 寸 由 包 括 在 标 准 头 文 件 STDDEF.H
中 的 类 型 ptrdiff _ t 定 义 。 其 结 果 是 表 示 两 个 地 址 之 间 相 差 的 存 储 器 位 置的 个 数 , 该 结 果 仅 对 相 同 数 组 的 两 个 元 素 才 是 有 意 义 的 , 正 如 “ 指 针 算 术 ” 中 讨 论 的 。
当 从 一 个 指 针 值 减 去 一 个 整 数 时 , 减 法 运 算 符 通 过 该 整 数 值 (i) 乘 以 该 指针 所 指 值 的 尺 寸 来 转 换 , 在 转 换 之 后 ,该 整 数 值 表 示 i 存 储 位 置 , 而 每 个 位置 都 有 该 指 针 类 型 所 指 的 长 度 。 当 从 该 指 针 值 减 去 该 转 换 的 整 数 值 时 , 其 结 果 是 最 初 地 址 的 前 i 个 存 储 器 位 置 。 新 的 指 针 指 向 最 初 指 针 值 所 指的 类 型 的 值 。
使 用 加 法 运 算 符
下 例 说 明 了 加 和 减 运 算 符 , 使 用 了 这 些 说 明 :
int i=4,j; float x[10]; float *px;
如 下 语 句 是 等 价 的 :
px=&x[4+i]; px=&x[4]+i;
i 的 值 乘 以 一 个 float 的 长 度 并 加 到 &x[4] 中 ,其 结 果 指 针 值 是 x[8] 的 地 址 。
j=&x[i]-&x[i-2 ];
在 这 个 例 子 中 , 从 x 的 第 五 个 元 素 的 地 址 ( 由 x[i] 给出 ) 减 去 x 的 第 三 个 元素 的 地 址 ( 由 x[i-2]给 出 )。 其 差 除 以 一 个 float 的 长 度 , 结 果 为 整 数 2 。
指 针 算 术
涉 及 到 一 个 指 针 和 一 个 整 数 的 加 法 运 算 只 存 在 该 指 针 操 作 数 指 向 一 个 数组 的 元 素 以 及 该 整 数 产 生 同 一 数 组 中 的 偏 移 量 时 才 有 意 义 。 当 该 整 数 值转 换 成 一 个 地 址 偏 移 量 时 , 编 译 器 假 设 只 有 相 同 尺 寸 的 存 储 器 位 置 位 于最 初 地 址 和 该 地 址 加 上 偏 离 量 的 结 果 之 间 。
对 于 数 组 成 员 这 个 假 设 是 有 效 的 。 通 过 定 义 , 一 个 数 组 是 相 同 类 型 的 值的 序 列 , 它 的 元 素 存 储 在 相 邻 存 储 器 位 置 。 但 除 数 组 外 , 其 它 任 何 类 型 的存 储 不 能 保 证 由 相 同 类 型 的 标 识 符 填 充 , 也 即 , 存 储 器 位 置 之 间 可 能 出 现空 格 , 即 使 相 同 类 型 的 位 置 也 是 如 此 。 因 此 , 除 数 组 元 素 外 任 何 值 的 地 址加 或 减 的 结 果 都 是 不 确 定 的 。
类 似 地 , 当 两 个 指 针 值 相 减 时 ,其 转 换 假 设 只 有 相 同 类 型 的 值 ,没 有 空 格 , 且在 操 作 数 给 定 的 地 址 空 间 。
按 位 位 移 运 算 符
位 移 运 算 符 左 移 (<< )或 右 移 (>>) 第 一 个 操 作 数 的 位 置 个 数 , 由 第 二 个 操作 数 指 定 。
语法
位移表达式 :
加法表达式
位移表达式 |
<< |
加法表达式 |
---|---|---|
位移表达式 |
>> |
加法表达式 |
两 个 操 作 数 必 须 是 整 数 值 , 这 些 运 算 符 执 行 常 用 的 算 术 转 换 , 其 结 果 的 类型 是 转 换 后 左 操 作 数 的 类 型 。
对 于 向 左 移 位 移 , 腾 出 的 右 边 位 设 置 为 0 。 对 于 向 右 位 移 , 腾 出 的 左 边 位基 于 转 换 后 第 一 个 操 作 数 的 类 型 进 行 填 充 。 如 果 该 类 型 是 unsigned, 它们 设 置 为 0 ;否 则 , 它 们 用 符 号 位 的 拷 贝 进 行 填 充 。 对 于 向 左 位 移 运 算 符 , 没 有 上 溢 出 ,语 句 :
expr1 << expr2
等 价 于 乘 以 2 expr2。 对 于 右 移 运 算 符 :
expr1 >> expr2
如 果 expr1 是 无 符 号 的 或 有 一 个 非 负 值 , 它 等 价 于 除 以 2 expr2。
如 果 第 二 个 操 作 数 是 负 数 , 或 者 如 果 右 操 作 数 大 于 或 等 于 提 升 的 左 操 作数 中 的 位 为 单 位 的 宽 度 , 则 一 个 位 移 运 算 的 结 果 是 不 确 定 的 。 由 于 位 移运 算 符 执 行 的 转 换 没 有 提 供 上 溢 出 或 下 溢 出 条 件 , 如 果 一 个 位 移 运 算 的结 果 不 能 由 转 换 后 第 一 个 操 作 数 的 类 型 所 表 示 ,则 可 能 丢 失 信 息 。
unsigned int x,y,z;
x=0x00AA; y=0x5500;
z=(x<<8)+(y>>8);
在 这 个 例 子 中 ,x 左 移 8 个 位 置 ,y 右 移 8 个 位 置 。 位 移 的 值 相 加 ,结 果 为
0 x AA55 并 赋 给 z 。 将 一 个 负 数 右 移 一 位 产 生 的 结 果 是 其 绝 对 值 舍 入 的
一 半 , 例 如 ,-253( 二 进 制 1111111100000011) 右 移 一 位 产 生 -127( 二 进 制
1111111110000001) 。 一 个 正 数 253 右 移 一 位 产 生 +126 。
右 移 保 留 符 号 位 。 当 一 个 有 符 号 整 数 右 位 移 时 , 保 留 设 置 最 重 要 的 位 。当 一 个 无 符 号 整 数 右 位 移 时 , 该 最 重 要 位 被 清 除 。
如 果 0xF000 是 无 符 号 数 ,其 结 果 是 0x7800 。 如 果 0xF0000000 是 有 符 号的 ,右 移 一 位 产 生 0xF8000000 。 右 移 一 个 正 数 32 次 产 生 0xF0000000 。右 移 一 个 负 数 32 次 产 生 0xFFFFFFFF 。
关 系 和 相 等 运 算 符
双 目 关 系 和 相 等 运 算 符 将 其 第 一 个 操 作 数 与 第 二 个 操 作 数 进 行 比 较 以 测试 指 定 关 系 的 有 效 性 。 如 果 测 试 的 关 系 为 真 ,则 该 关 系 表 达 式 的 结 果 为 1, 如 果 为 假 则 为 0 。 其 结 果 的 类 型 为 in t。
语法 :
关系表达式 :
位移表达式
关系表达式 < 位移表达式关系表达式 > 位移表达式关系表达式 <= 位移表达式
关系表达式 >= 位移表达式相等表达式 :
关系表达式
相等表达式 == 关系表达式
相等表达式 != 关 系 表 达 式
关 系 和 相 等 运 算 符 测 试 如 下 关 系 :
运算符 测试的关系
< 第一个操作数小于第二个操作数
> 第一个操作数大于第二个操作数
<= 第一个操作数小于或等于第二个操作数
>= 第一个操作数大于或等于第二个操作数
== 第一个操作数等于第二个操作数
!= 第一个操作数不等于第二个操作数
上 表 中 的 开 头 四 个 运 算 符 比 相 等 运 算 符 (== 和 != )具 有 更 高 的 优 先 级 。 参见 表 4.1 中 的 优 先 级 信 息 。
操 作 数 可 以 是 整 数 、 浮 点 或 指 针 类 型 。 操 作 数 的 类 型 可 以 不 同 。 关 系 运算 符 在 整 数 和 浮 点 类 型 操 作 数 上 执 行 常 用 的 算 术 转 换 。 另 外 , 你 可 以 用关 系 和 相 等 运 算 符 构 成 如 下 操 作 数 类 型 的 组 合 :
- 任 何 关 系 或 相 等 运 算 符 的 两 个 操 作 数 可 以 是 相 同 类 型 的 指 针 。 对 于等 于 (==) 和 不 等 于 (!=) 运 算 符 , 比 较 的 结 果 指 出 两 个 指 针 是 否 指向 相 同 存 储 器 位 置 。 对 于 其 它 关 系 运 算 符 (< 、 > 、 <= 和 >=), 比 较 的结 果 指 出 所 指 对 象 的 两 个 存 储 器 位 置 之 间 的 关 系 。 关 系 运 算 符 仅 比较 偏 移 量 。
只 对 相 同 对 象 的 部 分 定 义 了 指 针 比 较 。 如 果 该 指 针 指 向 一 个 数 组 的成 员 , 该 比 较 等 价 于 对 应 下 标 的 比 较 。 第 一 个 数 组 元 素 的 地 址 “ 小于 ” 最 后 一 个 元 素 的 地 址 。 在 结 构 的 情 况 下 , 后 面 说 明 的 结 构 成 员
的 指 针 “ 大 于 ” 前 面 说 明 的 结 构 成 员 的 指 针 。 对 于 同 一 联 合 成 员 的指 针 是 相 等 的 。
-
一 个 指 针 值 可 以 与 常 量 值 0 比 较 是 相 等 (==) 或 不 相 等 (!=) 。 具 有 0 值 的 指 针 称 为 “ 空 ” 指 针 , 也 就 是 , 它 不 指 向 任 何 有 效 的 存 储 器 位 置 。
-
相 等 运 算 符 遵 守 与 关 系 运 算 符 相 同 的 规 则 , 但 允 许 另 外 的 可 能 : 一 个指 针 可 以 与 一 个 具 有 0 值 的 常 量 整 数 表 达 式 或 与 void 的 指 针 进 行比 较 。 如 果 两 个 指 针 都 为 空 指 针 , 它 们 是 相 等 的 。 相 等 运 算 符 比 较两 个 段 和 偏 移 量 。
例 子
如 下 例 子 说 明 关 系 和 相 等 运 算 符
int x=0,y=0 ; if (x<y)
因 为 x 和 y 相 等 ,这 个 例 子 中 的 表 达 式 产 生 值 0 。
char array[10]; char *p;
for (p=array;p<&array[10];p++)
*p= ′ \0 ′ ;
本 例 中 的 段 设 置 array 的 每 个 元 素 为 一 个 空 字 符 常 量 。
enum color {red,white,green} col;
.
.
.
.
if (col==red)
这 些 语 句 用 标 志 color 说 明 一 个 名 称 为 col 的 枚 举 变 量 。 在 任 何 时 候 , 该变 量 可 以 包 含 0 、 1 或 2 的 一 个 整 数 值 , 它 表 示 枚 举 集 color: 分 别 为 红 、白 和 绿 之 一 。 当 执 行 if 语 句 时 如 果 col 包 含 0 ,则 执 行 依 赖 该 if 的 任 何 语句 。
按 位 运 算 符
按 位 运 算 符 执 行 按 位 AND(& )、 按 位 异 或 (^ )和 按 位 OR(|) 运 算 。
语法
A N D 表达式 :
相等表达式
AND 表达式 & 相等表达式异或表达式 :
AND 表达式
异或表达式 ^ AND 表达式
O R 表 达 式 :
异或表达式
O R 表达式 | 异或表达式
按 位 运 算 符 的 操 作 数 必 须 有 整 数 类 型 , 但 它 们 的 类 型 可 能 不 同 。 这 些 运算 符 执 行 常 用 的 算 术 转 换 。 其 结 果 的 类 型 是 转 换 后 操 作 数 的 类 型 。
C 按 位 运 算 符 描 述 如 下 :
运算符 说明
& 按位 AND 运算符将第一个操作数的每个位与第二个操作数的对应位进行比较 , 如 果 两 个 位 都 为 1, 对应的结果位设置为 1; 否则 , 对应的结果位设置为 0 。
^ 按 位 异 或 运 算 符 将 第 一 个 操 作 数 的 每 个 位 与 第 二 个 操 作 数 的 对 应位进行比较 , 如果一个位为 0 而另一位为 1, 对应的结果位设置为
1, 否则 , 对应的结果位设置为 0
| 按位 OR 运 算 符 将 第 一 个 操 作 数 的 每 个 位 与 第 二 个 操 作 数 的 对 应位进行比较 , 如 果 有 一 个 位 为 0, 对应的结果位设置为 1; 否则 , 对应的结果位设置为 1
例 子
这 些 说 明 用 于 如 下 三 个 例 子 :
short i=0xAB00; short i=0xABCD; short n;
n=i&j;
在第一个例子中赋给 n 的结果与 i 的值 ( 十六进制 0xAB00) 相同。
n=i|j; n=i^j;
在 第 二 个 例 子 中 按 位 OR 产 生 结 果 0xABCD( 十 六 进 制 数 ), 而 在 第 三 个 例 子 中 的 按位 异 或 产 生 0xCD( 十 六 进 制 数 ) 。
Microsoft 特 殊 处 →
在 有 符 号 整 数 上 按 位 运 算 的 结 果 是 根 据 ANSI C 标 准 实 现 定 义 的 。 对 于 C 编 译 器 , 在 有 符 号 整 数 上 的 按 位 运 算 与 在 无 符 号 整 数 上 的 按 位 运 算 相 同 。 例 如 ,
-16&99 可 以 以 二 进 制 表 示 为 :
11111111 11110000
& 00000000 01100011
------------------- 00000000 01100000
该 按 位 AND 的 结 果 是 十 进 制 96 。
Microsoft 特 殊 处 结 束逻 辑 运 算 符
逻 辑 运 算 符 执 行 逻 辑 AND(&& ) 和 逻 辑 OR(||) 运 算 。
语法
逻辑 A N D 表 达 式
OR 表达式
逻辑 A N D 表达式 & & O R 表达式
O R 表 达 式 :
逻辑 A N D 表 达 式
逻辑 A N D 表 达 式 || 逻辑 A N D 表 达 式
逻 辑 运 算 符 不 执 行 常 用 的 算 术 转 换 。 代 替 地 , 它 们 根 据 它 的 0 的 等 值 对每 个 操 作 数 进 行 求 值 ,一 个 逻 辑 运 算 的 结 果 为 0 或 1, 其 结 果 的 类 型 为 in t。C 逻 辑 运 算 符 描 述 如 下 :
运算符 说明
&& 如果两个操作数都为非 0 值 , 则逻辑 AND 运算符产生值 1 。如果有 一 个 操 作 数 为 0, 其 结 果 为 0 。 如 果 一 个 逻 辑 AND 运算的第一个操作数等于 0, 第二个操作数不求值
|| 逻辑 OR 运算符在其操作数上执行一个 OR 运算。如果两个操作数都为 0 值 , 其结果为 0 。如果有一个操作数为非 0 值 , 其结果为1 。如果一个逻辑 OR 运算符的第一个操作数为非 0 值 , 则第二个操作数不求值
逻 辑 AND 和 逻 辑 OR 表 达 式 的 操 作 数 从 左 到 右 求 值 。 如 果 第 一 个 操 作
数 的 值 能 够 足 够 确 定 该 运 算 的 结 果 , 则 第 二 个 结 果 数 不 进 行 求 值 , 这 称 为“ 短 路 求 值 ”。 在 第 一 个 操 作 数 之 后 有 一 个 顺 序 点 。 有 关 更 多 信 息 参 见本 章 前 面 的 “ 顺 序 点 ”。
例 子
如 下 例 子 说 明 逻 辑 运 算 符 :
int w,x,y,z;
if (x<y && y<z)
printf("x is less than z\n");
在 这 个 例 子 中 , 如 果 x 小 于 y 且 y 小 于 z 则 调 用 printf 函 数 打 印 一 个 消 息 。
如 果 x 大 于 y, 第 二 个 操 作 数 (y<z) 不 求 值 且 不 打 印 该 消 息 。 注 意 , 在 这种 情 况 可 能 出 现 问 题 ,第 二 个 操 作 数 由 于 某 些 其 它 原 因 而 有 副 作 用 。 printf ("%d",(x==w || x==y || x==z));
在 这 个 例 子 中 , 如 果 x 等 于 w 和 y 或 z,printf 函 数 的 第 二 个 求 值 为 真 时 打
印 1 ;否 则 ,求 值 假 时 打 印 0 。 只 要 条 件 之 一 求 值 为 真 ,则 求 值 停 止 。
条 件 表 达 式 运 算 符
C 有 一 个 三 元 运 算 符 : 条 件 表 达 式 运 算 符 (?:) 。
语法
条件表达式 :
逻辑 O R 表达式
逻辑 O R 表达式 ? 表达式 : 条件表达式
逻 辑 O R 表 达 式 必 须 具 有 整 数 、 浮 点 或 指 针 类 型 。 根 据 等 值 于 0 的 方 式进 行 求 值 。 一 个 顺 序 点 紧 跟 逻 辑 O R 表 达 式 。 操 作 数 求 值 过 程 如 下 :
-
如 果 逻 辑 OR 表 达 式 不 等 于 0 表 达 式 求 值 。 该 结 果 由 非 终 结 符 表 达式 给 出 ( 这 意 味 着 表 达 式 仅 在 逻 辑 OR 表 达 式 为 真 时 求 值 ) 。
-
如 果 逻 辑 OR 表 达 式 等 于 0, 条 件 表 达 式 求 值 。 该 结 果 是 其 条 件 表 达式 的 值 ( 这 意 味 着 仅 在 逻 辑 OR 表 达 式 为 假 时 对 条 件 表 达 式 求 值 ) 。
注 意 , 表 达 式 或 条 件 表 达 式 之 一 求 值 ,但 不 是 两 者 。
- 个 条 件 表 达 式 结 果 的 类 型 依 赖 于 表 达 式 或 条 件 表 达 式 操 作 数 的 类 型 如下 :
- 如 果 表 达 式 或 条 件 表 达 式 具 有 整 数 或 浮 点 类 型 ( 它 们 的 类 型 可 以 不
同 ), 该 运 算 符 执 行 常 用 的 算 术 转 换 。 该 结 果 的 类 型 是 转 换 后 操 作 数的 类 型 。
-
如 果 表 达 式 和 条 件 表 达 式 具 有 相 同 的 结 构 、 联 合 或 指 针 类 型 , 该 结果 类 型 是 同 样 的 结 构 、 联 合 或 指 针 类 型 。
-
如 果 两 个 操 作 数 都 具 有 void 类 型 , 该 结 果 是 void 类 型 。
-
如 果 操 作 数 之 一 为 任 何 类 型 的 一 个 对 象 的 指 针 , 另 一 个 操 作 数 是 一个 void 的 指 针 , 该 对 象 的 指 针 转 换 成 一 个 void 的 指 针 , 该 结 果 是 一个 void 的 指 针 。
-
如 果 表 达 式 或 条 件 表 达 式 之 一 是 一 个 指 针 , 另 一 个 操 作 数 是 一 个 具有 0 值 的 常 量 表 达 式 。 该 结 果 的 类 型 是 void 的 指 针 。
在 指 针 的 类 型 比 较 中 , 该 指 针 所 指 的 类 型 中 的 任 何 类 型 修 饰 符 (const 或volatile)都 是 不 重 要 的 。 但 结 果 类 型 以 两 个 条 件 的 组 成 成 分 继 承 修 饰 符 。例 子
如 下 例 子 说 明 条 件 运 算 符 的 使 用
j=(i<0) ? (-i) : (i);
这 个 例 子 把 i 的 绝 对 值 赋 给 j。 如 果 i 小 于 0 ,则 把 -i 赋 给 j;如 果 i 大 于 或等 于 0,i 赋 给 j 。
void f1(void); void f2(void); int x;
int y;
.
.
.
(x == y) ? (f1()) : (f2());
在 这 个 例 子 中 , 说 明 了 两 个 函 数 f1 和 f2 以 及 两 个 变 量 x 和 y 。 在 程 序 后面 ,如 果 这 两 个 变 量 具 有 相 同 的 值 , 则 调 用 f1 函 数 ; 否 则 调 用 f2 函 数 。
赋 值 运 算 符
一 个 赋 值 运 算 把 右 边 操 作 数 的 值 赋 给 左 边 操 作 数 命 名 的 存 储 位 置 。因此 , 一 个 赋 值 运 算 的 左 边 操 作 数 必 须 是 可 修 改 的 l 值 。 在 赋 值 之 后 , 一 个 赋 值表 达 式 具 有 左 边 操 作 数 的 值 , 但 不 是 一 个 l 值 。
语法
赋值表达式 :
条件表达式
单目表达式 赋值运算符 赋值表达式
赋 值 运 算 符 :如 下 之 一
= *= /= %= += -= <<= >>= &= ^= |+
C 中 的 赋 值 运 算 符 可 以 在 单 个 运 算 中 进 行 转 换 和 赋 值 。 C 提 供 了 如 下 赋值 运 算 符 :
运算符 执行的运算
= 简单赋值
*= 乘法赋值
/= 除法赋值
%= 余数赋值
+= 加法赋值
-= 减法赋值
<<= 左位移赋值
>>= 右位移赋值
&= 按位 AND 赋值
^= 按位异或赋值
|+ 按位或赋值
在 赋 值 中 , 右 边 值 的 类 型 转 换 成 左 边 值 的 类 型 , 并 在 赋 值 发 生 后 把 该 值存 储 在 左 边 操 作 数 中 。 左 边 操 作 数 不 能 是 数 组 、 函 数 或 常 量 。 在 本 章 后面 的 “ 类 型 转 换 ” 中 详 细 讨 论 了 指 定 的 转 换 路 径 , 它 依 赖 于 两 种 类 型 。
简 单 赋 值
简 单 赋 值 运 算 符 把 它 的 右 操 作 数 赋 给 左 操 作 数 。 右 操 作 数 的 值 转 换 成 赋值 表 达 式 的 类 型 , 并 替 换 存 储 在 左 操 作 数 指 定 的 对 象 中 的 值 。 应 用 赋 值的 转 换 规 则 ( 参 见 本 章 后 面 的 “ 赋 值 转 换 ” )。
double x;
int y;
x=y;
在 这 个 例 子 中 ,y 的 值 转 换 成 double 类 型 并 赋 给 x 。
复 合 赋 值
复 合 赋 值 运 算 符 组 合 简 单 赋 值 运 算 符 和 其 它 双 目 运 算 符 。 复 合 赋 值 运 算符 执 行 另 外 运 算 符 指 定 的 运 算 , 然 后 把 结 果 赋 给 左 操 作 数 。 例 如 , 这 样 的一 个 复 合 赋 值 表 达 式 :
expression1+=expression2
可 以 理 解 为
expression1=expression1+expression2
但 复 合 赋 值 表 达 式 不 等 于 扩 充 的 版 本 , 因 为 在 加 法 运 算 中 和 在 赋 值 运 算中 , 复 合 赋 值 表 达 式 仅 求 值 expression1 一 次 , 而 扩 充 的 版 本 求 值expression1 两 次 。
一 个 复 合 赋 值 运 算 符 的 操 作 数 必 须 是 整 数 或 浮 点 类 型 。 每 个 复 合 赋 值 运算 符 执 行 对 应 的 双 目 运 算 符 执 行 的 转 换 , 并 相 应 地 限 制 它 的 操 作 数 的 类型 。 加 法 赋 值 (+=) 和 减 法 赋 值 (-= )运 算 符 也 有 一 个 指 针 类 型 的 左 操 作 数 , 在 这 种 情 况 下 右 边 操 作 数 必 须 是 整 数 类 型 。 一 个 复 合 操 作 数 的 结 果 具 有左 操 作 数 的 值 和 类 型 。
#define MASK 0xff00 n&=MASK;
在 这 个 例 子 中 , 在 n 和 MASK 上 执 行 一 个 按 位 AND 运 算 ,并 把 结 果 赋 给
n 。 显 式 常 量 MASK 用 一 个 #define 预 处 理 器 命 令 定 义 。
顺 序 求 值 运 算 符
顺 序 求 值 运 算 符 也 称 为 “ 逗 号 运 算 符 ” , 从 左 向 右 顺 序 计 算 它 的 两 个 操作 数 。
语 法 表达式 :
赋值表达式
表达式 ,赋 值 表 达 式
顺 序 求 值 运 算 符 的 左 操 作 数 作 为 一 个 void 表 达 式 求 值 。 该 运 算 的 结 果具 有 和 右 操 作 数 相 同 的 值 和 类 型 , 每 个 操 作 数 可 以 是 任 何 类 型 。 顺 序 求值 运 算 符 在 它 的 操 作 数 之 间 不 执 行 任 何 类 型 转 换 , 它 不 产 生 l 值 。 在 第 一个 操 作 数 之 后 产 生 一 个 顺 序 点 , 这 意 味 着 从 左 操 作 数 求 值 产 生 的 副 作 用在 右 操 作 数 求 值 开 始 之 前 均 已 完 成 。 有 关 更 多 信 息 ,参 见 本 章 前 面 的“ 顺序 点 ”。
顺 序 求 值 运 算 符 通 常 用 于 对 上 下 文 中 两 个 或 多 个 表 达 式 求 值 , 而 这 里 仅允 许 一 个 表 达 式 。
逗 号 在 某 些 上 下 文 中 用 作 分 隔 符 , 但 你 必 须 小 心 不 要 将 它 作 为 分 隔 符 使用 和 作 为 运 算 符 使 用 相 混 淆 , 这 两 种 使 用 是 完 全 不 同 的 。
例 子
这 个 例 子 说 明 顺 序 求 值 运 算 符 :
for (i=j=1;i+j<20;i+=i,j--);
在 这 个 例 子 中 ,for 语 句 的 第 三 个 表 达 式 的 每 个 操 作 数 都 分 开 求 值 。 左 操作 数 i+=i 首 先 求 值 ,然 后 是 右 操 作 数 j-- 求 值 。
func_one (x,y+2,z); func_two((x--,y+2),z);
在 func_one 函 数 调 用 中 , 三 个 用 逗 号 隔 开 的 参 量 分 别 传 送 给 :x,y+2 和 z 。
在 func_two 函 数 调 用 中 , 圆 括 号 强 制 编 译 器 解 释 第 一 个 逗 号 为 顺 序 求 值运 算 符 。 这 个 函 数 调 用 传 送 两 个 参 量 给 func_two, 第 一 个 参 量 是 顺 序 求值 运 算 (x--,y+2) 的 结 果 ,它 具 有 y+2 表 达 式 的 值 和 类 型 , 第 二 个 参 量 是 z 。
类 型 转 换
类 型 转 换 依 赖 于 指 定 的 运 算 符 和 操 作 数 或 运 算 符 的 类 型 。 类 型 转 换 在 如下 情 况 下 执 行 :
-
当 一 个 类 型 的 值 赋 给 不 同 类 型 的 变 量 时 , 是 或 者 一 个 运 算 符 在 执 行该 运 算 之 前 转 换 它 的 一 个 操 作 数 或 多 个 操 作 数 的 类 型 时 。
-
当 一 个 类 型 的 值 显 式 造 型 转 换 为 一 个 不 同 的 类 型 时 。
-
当 一 个 值 作 为 一 个 参 量 传 送 给 一 个 函 数 或 者 当 从 一 个 函 数 返 回 一 个类 型 时 。
-
一 个 字 符 、 一 个 短 整 数 、 一 个 整 数 位 域 、 所 有 有 符 号 的 或 无 符 号 的或 者 枚 举 类 型 的 一 个 对 象 都 可 以 用 在 表 达 式 能 够 使 用 整 数 的 地 方 。如 果 一 个 int 可 以 表 示 所 有 最 初 类 型 的 值 , 那 么 该 值 转 换 成 int, 否
赋 值 转 换
则 , 它 转 换 成 unsigned int 。 这 个 过 程 称 为 “ 整 数 提 升 ”。 整 数 提 升保 持 值 , 也 就 是 , 在 提 升 之 后 的 值 保 证 与 提 升 前 的 值 相 同 。 有 关 更 多信 息 参 见 本 章 前 面 的 “ 常 用 的 算 术 转 换 ”。
在 赋 值 运 算 中 , 赋 值 的 类 型 转 换 成 接 受 赋 值 的 变 量 的 类 型 。 C 允 许 整 数和 浮 点 类 型 之 间 通 过 赋 值 进 行 转 换 , 即 使 在 转 换 中 选 择 信 息 也 如 此 。 使用 的 转 换 方 法 依 赖 于 赋 值 中 涉 及 的 类 型 , 正 如 “ 常 用 的 算 术 转 换 ” 和 如下 小 节 描 述 的 :
-
从 有 符 号 整 数 类 型 转 换
-
从 无 符 号 整 数 类 型 转 换
-
从 浮 点 类 型 转 换
-
从 指 针 类 型 转 换 和 转 换 到 指 针 类 型
-
从 其 它 类 型 转 换
类 型 修 饰 符 不 影 响 转 换 的 允 许 性 ,虽 然 一 个 const l 值 不 能 用 作 赋 值 的 左边 。
从 有 符 号 整 数 类 型 转 换
当 一 个 有 符 号 整 数 用 相 等 或 更 大 的 尺 寸 转 换 成 一 个 无 符 号 整 数 , 且 该 有符 号 整 数 不 是 负 数 时 , 该 值 不 改 变 。 通 过 符 号 扩 充 该 有 符 号 整 数 来 进 行转 换 , 一 个 有 符 号 整 数 通 过 高 端 的 位 转 换 成 一 个 更 短 的 有 符 号 整 数 , 其 结果 解 释 为 一 个 无 符 号 整 数 , 如 下 例 子 :
int i=-3;
unsig n ed short u;
u=i;
printf("%hu\n",u); /* 打 印 65533*/
当 一 个 有 符 号 整 数 转 换 成 一 个 浮 点 类 型 时 , 没 有 信 息 丢 失 , 除 当 一 个 long int 或 unsigned long int 值 转 换 成 一 个 float 值 可 能 丢 失 某 些 精 度 外 。
表 4.2 总 结 了 有 符 号 整 数 类 型 的 转 换 。 这 个 表 假 设 缺 省 char 类 型 为 有 符号 的 。 如 果 你 使 用 一 个 编 译 选 项 改 变 缺 省 char 类 型 为 无 符 号 的 , 这 个 转换 在 表 4.3 中 给 出 ,即 应 用 unsigned char 类 型 代 替 表 4.2 中 的 转 换 。
表 4.2 有 符 号 整 数 类 型 的 转 换
从 |
到 |
方法 |
---|---|---|
char 1 |
short |
符号扩充 |
char |
long |
符号扩充 |
char |
unsigned char |
保留模式 , 丢失高端作为符号的位 |
char |
unsigned short |
符 号 扩 充 为 short, 转 换 short 为 unsigned |
char |
unsigned long |
short 符号扩充为 long, 转换 long 为 unsigned long |
char |
float |
符号扩充为 long, 转换 long 为 float |
char |
double |
符号扩充为 long, 转换 long 为 double |
char |
long double |
符号扩充为 long, 转换 long 为 double |
续 表
从 到 方法
short Char 保留低端字节
short long 符号扩充short unsigned char 保留低端字节
short unsigned short 保留模式 , 丢失高端作为符号位的位
short unsigned long 符号扩充为 long, 转换 long 为 unsigned long short float 符号扩充为 long, 转换 long 为 float
short double 符号扩充为 long, 转换 long 为 double short long double 符号扩充为 long, 转换 long 为 double long char 保留低端字节
long short 保留低端字long unsigned char 保留低端字节long unsigned short 保留低端字
long unsigned long 保留模式 , 丢失高端作为符号位的位
l o ng float 作为 float 表示 , 如果 long 不能精确表示 , 丢
失精度
long double 作 为 double 表 示 , 如 果 long 不 能 作 为 一 个
double 精确表示 , 丢失精度
long long double 作 为 double 表 示 , 如 果 long 不 能 作 为 一 个
double 精确表示 , 丢失精度
1. 所 有 char 项 假 设 char 类 型 缺 省 是 有 符 号 的 。
Microsoft 特 殊 处 →
对 于 一 个 Microsoft 32 位 C 编 译 器 , 一 个 整 数 等 价 于 long 。 一 个 int 值 转换 处 理 与 long 的 相 同 。
Microsoft 特 殊 处 结 束
从 无 符 号 整 数 类 型 转 换
一 个 无 符 号 整 数 通 过 截 除 高 端 的 位 转 换 成 一 个 更 短 的 无 符 号 或 有 符 号 整数 ,或 者 通 过 0 扩 充 (参 见 表 4.3 )转 换 成 一 个 更 长 的 无 符 号 或 有 符 号 整 数 。当 整 数 类 型 的 值 用 更 小 的 尺 寸 降 级 为 一 个 有 符 号 整 数 , 或 者 一 个 无 符 号整 数 转 换 成 它 对 应 的 有 符 号 整 数 时 , 如 果 它 能 在 新 类 型 中 表 示 则 不 改 变它 的 值 。 但 如 果 设 置 符 号 位 , 则 它 表 示 的 值 发 生 改 变 ,如 下 例 子 :
int j;
unsigned short k=65533;
j=k;
printf("%hd\n",j); /* 打印 -3*/
如 果 它 不 能 表 示 , 其 结 果 是 实 现 定 义 的 。 有 关 C 编 译 器 处 理 整 数 降 级 的更 多 信 息 , 参 见 本 章 后 面 “ 类 型 造 型 转 换 ”。 从 整 数 类 型 转 换 或 从 造 型 整数 类 型 的 转 换 的 结 果 相 同 。
无 符 号 值 只 能 以 保 留 它 们 的 值 的 方 式 进 行 转 换 ,在 C 中 是 不 可 直 接 表 示的 。 唯 一 的 异 常 是 从 unsigned long 转 换 到 float, 它 丢 失 了 最 重 要 的 低 端位 。 否 则 保 留 值 , 无 论 是 有 符 号 的 还 是 无 符 号 的 。 当 一 个 整 数 类 型 的 值
转 换 成 浮 点 时 ,该 值 超 过 了 表 示 范 围 ,其 结 果 是 不 可 预 料 的 ( 有 关 整 数 和 浮点 类 型 的 范 围 的 信 息 , 参 见 第 3 章 “ 说 明 和 类 型 ” 中 的 “ 基 本 类 型 的 存储 ” )。
表 4.3 总 结 了 从 无 符 号 整 数 类 型 的 转 换 。
表 4.3 从 无 符 号 整 数 类 型 的 转 换
从 |
到 |
方法 |
|
---|---|---|---|
unsigned char |
char |
保留位模式 , 高端位变成符号位 |
|
unsigned char |
short |
0 |
扩充 |
unsigned char |
long |
0 |
扩充 |
unsigned char |
unsigned short |
0 |
扩充 |
unsigned char |
unsigned long |
0 |
扩充 |
unsigned char |
float |
转换为 long, 转换 long 为 |
float |
unsigned char |
double |
转换为 long, 转换 long 为 |
double |
unsigned char unsigned short |
long double char |
转换为 long, 转换 long 为 保留低端字节 |
double |
unsigned short |
short |
保留位模式 , 高端位变成符号位 |
|
unsigned short |
long |
0 扩充 |
|
unsigned short |
unsigned char |
保留低端字节 |
|
unsigned short |
unsigned long |
0 扩充 |
|
unsigned short |
float |
转换为 long, 转换 long 为 float |
|
unsigned short |
double |
转换为 long, 转换 long 为 double |
|
unsigned short |
long double |
转换为 long, 转换 long 为 double |
|
unsigned long |
char |
保留低端字节 |
续 表
unsigned long Short 保留低端字
unsigned long long 保留位模式 , 高端位变成符号位unsigned long unsigned char 保留低端字节
unsigned long unsigned short 保留低端字
unsigned long float 转换为 long, 转换 long 为 float
unsigned long double 直接转换为 double
unsigned long long double 转换为 long, 转换 long 为 double
Microsoft 特 殊 处 →
对 于 Microsoft 32 位 C 编 译 器 ,unsigned int 类 型 等 价 于 unsigned long 类型 。 一 个 unsigned int 值 的 转 换 的 方 式 与 一 个 unsigned long 的 转 换 方 式相 同 。 如 果 转 换 的 值 大 于 最 大 正 的 有 符 号 long 值 ,那 么 从 unsigned long 值 转 换 到 float 是 不 准 确 的 。
Microsoft 特 殊 处 结 束
从 浮 点 类 型 转 换
一 个 float 值 可 以 转 换 成 一 个 double 或 long double , 或 者 一 个 double 转换 成 一 个 long double ,不 改 变 其 中 的 值 。 如 果 可 能 ,一 个 double 值 转 换 成一 个 准 确 表 示 的 float 值 。 如 果 该 值 不 能 准 确 表 示 ,则 可 能 丢 失 精 度 。 如果 结 果 超 出 了 范 围 ,其 行 为 是 不 可 确 定 的 。 有 关 浮 点 类 型 的 范 围 , 参 见 第1 章 “ C 的 基 本 元 素 ” 中 的 “ 浮 点 常 量 的 限 制 ”。
通 过 把 一 个 浮 点 值 先 转 换 成 一 个 long, 然 后 把 该 long 值 转 换 成 指 定 的 整数 值 , 正 如 表 4.4 所 说 明 的 ,把 该 浮 点 值 转 换 成 一 个 整 数 值 , 在 转 换 成 long
中 ,丢 弃 该 浮 点 值 的 小 数 部 分 。 如 果 仍 太 大 不 适 合 long 表 示 ,则 该 转 换 的结 果 是 不 确 定 的 。
Microsoft 特 殊 处 →
当 把 一 个 double 或 long double 浮 点 数 转 换 成 一 个 较 小 的 浮 点 数 时 , 如 果发 生 下 溢 出 则 朝 向 0 截 除 该 浮 点 数 的 值 。 一 个 上 溢 出 导 致 一 个 运 行 错误 。 注 意 , C 编 译 器 把 long double 映 射 成 double 。
Microsoft 特 殊 处 结 束
表 4.4 总 结 了 从 浮 点 类 型 的 转 换 。
表 4.4 从 浮 点 类 型 的 转 换
从 |
到 |
方法 |
---|---|---|
float |
char |
转换为 long; 转换 long 为 char |
float |
short |
转换为 long; 转换 long 为 short |
float |
long |
在 小 数 点 处 截 除 。 如 果 结 果 太 大 不 能 表 示 成 |
long, 则其结果是不确定的 |
float unsigned short
float unsigned long
转换为 long, 转换 long 为 unsigned short 转换为 long, 转换 long 为 unsigned long
float double 改变内部表示float long chouble 改变内部表示
double char 转换为 float, 转换 float 为 char
续 表
从 到 方法
double short 转换为 float, 转换 float 为 short
double long 在小数点处截除。如果该结果太大不能用 long
表示 , 则结果是不确定的
double unsigned short
double unsigned long
转换为 long, 转换 long 为 unsigned short 转换为 long, 转换 long 为 unsigned long
double float 表示为 float 。如果 double 值不能以 float 类
型 准 确 地 表 示 , 会 出 现 精 度 丢 失 。 如 果 该 值 太大不能作为 float 表示 , 其结果是不确定的
long double
char 转换为 float, 转换 float 为 char
long doubl short 转换为 float, 转换 float 为 short
long double
long 在 小 数 点 处 截 除 。 如 果 结 果 太 大 不 能 用 long 表示 , 则结果是不确定的
long double long double
unsigned short unsigned long
转换为 long; 转换 long 为 unsigned short 转换为 long; 转换 long 为 unsigned long
long double
long double
续 表
float 表示为 float 。如果 double 值不能以 float 类型 准 确 地 表 示 , 会 出 现 精 度 丢 失 。 如 果 该 值 太大不能作为 float 表示 , 其结果是不确定的
double 该 long double 值作为 double 处理
如 果 被 转 换 的 值 大 于 最 大 正 数 long 值 ,则 从 float、 double 或 long double
值 到 unsigned long 的 转 换 是 不 准 确 的 。
转 换 到 指 针 类 型 和 从 指 针 类 型 转 换
-
个 值 类 型 的 指 针 可 以 转 换 成 一 个 不 同 类 型 的 指 针 。 虽 然 这 个 结 果 可 能因 为 对 齐 要 求 和 不 同 类 型 的 存 储 尺 寸 而 导 致 其 结 果 是 不 确 定 的 。 一 个 对象 的 指 针 可 以 转 换 成 一 个 其 类 型 需 要 较 少 或 完 全 相 同 的 对 象 的 指 针 , 反过 来 没 有 改 变 。
-
个 void 的 指 针 可 以 转 换 成 任 何 类 型 的 一 个 指 针 ,或 者 从 任 何 类 型 的 指针 可 以 转 换 成 一 个 void 的 指 针 。 如 果 其 结 果 被 回 过 来 转 换 成 最 初 的 类型 ,则 恢 复 最 初 的 指 针 。
如 果 一 个 指 针 转 换 成 另 一 个 指 针 , 后 者 有 相 同 的 类 型 , 但 有 不 同 的 或 另 外的 修 饰 符 ,该 新 的 指 针 与 老 的 指 针 相 同 ,除 了 强 制 加 上 新 的 修 饰 符 之 外 。一 个 指 针 值 也 可 以 转 换 成 一 个 整 数 值 。 根 据 如 下 规 则 , 其 转 换 路 径 依 赖于 该 指 针 的 尺 寸 和 整 数 类 型 的 尺 寸 :
- 如 果 指 针 的 尺 寸 大 于 或 等 于 该 整 数 的 尺 寸 , 该 指 针 的 行 为 在 转 换 中
像 一 个 无 符 号 值 一 样 , 除 了 它 不 能 转 换 成 一 个 浮 点 值 外 。
- 如 果 该 指 针 小 于 整 数 类 型 , 首 先 把 该 指 针 转 换 成 一 个 与 整 数 类 型 相同 尺 寸 的 指 针 , 然 后 再 转 换 成 整 数 类 型 。
相 反 地 , 一 个 整 数 类 型 也 可 以 根 据 如 下 规 则 转 换 成 一 个 指 针 类 型 :
-
如 果 该 整 数 类 型 与 指 针 类 型 具 有 相 同 的 尺 寸 , 简 单 地 转 换 该 整 数 值作 为 一 个 指 针 ( 一 个 无 符 号 整 数 ) 处 理 。
-
如 果 该 整 数 的 尺 寸 不 同 于 该 指 针 类 型 的 尺 寸 , 首 先 把 整 数 类 型 转 换成 该 指 针 的 尺 寸 , 这 里 使 用 表 4.2 和 表 4.3 中 给 出 的 转 换 路 线 ; 然后 把 它 作 为 一 个 指 针 值 处 理 。
- 个 具 有 0 型 的 整 数 常 量 表 达 式 或 一 个 强 制 造 型 为 类 型 void * 的 表 达 式可 以 通 过 一 个 类 型 造 型 、 赋 值 或 与 任 何 类 型 的 指 针 进 行 比 较 来 转 换 。 这产 生 一 个 等 于 另 一 个 相 同 类 型 空 指 针 的 空 指 针 , 但 这 个 空 指 针 不 等 于 一个 函 数 或 一 个 对 象 的 任 何 指 针 。 不 为 常 量 0 的 其 它 整 数 也 可 以 转 换 成 指针 类 型 , 但 其 结 果 不 是 可 移 植 的 。
从 其 它 类 型 转 换
由 于 一 个 enum 值 是 一 个 定 义 的 int, 从 一 个 enum 值 转 换 或 转 换 到 enum 值 与 int 类 型 的 方 式 相 同 。 对 于 C 编 译 器 , 一 个 整 数 与 一 个 long 是 相 同的 。
Microsoft 特 殊 处 →
结 构 或 联 合 类 型 之 间 不 允 许 转 换 。
任 何 值 可 以 转 换 成 类 型 void, 但 这 个 转 换 的 结 果 仅 用 在 一 个 表 达 式 值 被
丢 弃 的 上 下 文 中 , 例 如 在 一 个 表 达 式 语 句 中 。
由 定 义 , void 类 型 没 有 值 ,因 此 它 不 能 转 换 成 任 何 其 它 类 型 ,其 它 类 型 也不 能 通 过 赋 值 转 换 成 void ,然 而 你 可 以 显 式 造 型 转 换 一 个 值 为 类 型 void, 正 如 下 一 节 “ 类 型 造 型 转 换 ” 中 讨 论 的 。
Microsoft 特 殊 处 结 束
类 型 造 型 转 换
你 可 以 使 用 类 型 造 型 显 式 转 换 类 型 。
语法
造型表达式 :
单目表达式
(类 型 名 称 )造 型 表 达 式类型名称 :
指示符修饰符表 抽象说明符 opt
类 型 名 称 是 一 个 类 型 ,造 型 表 达 式 是 要 转 换 成 这 个 类 型 的 值 。 一 个 带 有
类 型 造 型 的 表 达 式 不 能 是 一 个 l 值 。 造 型 表 达 式 是 被 转 换 赋 给 类 型 名 称指 定 类 型 的 变 量 。 赋 值 的 转 换 规 则 ( 在 前 面 “ 赋 值 转 换 ” 中 描 述 ) 也 适 用于 类 型 造 型 。
表 4.5 说 明 了 可 以 造 型 转 换 为 给 定 类 型 的 类 型 。
表 4 .5 合 法 的 类 型 造 型
目的类型 |
可能的源 |
||||||
---|---|---|---|---|---|---|---|
整数类型 浮点类型 |
任 何 整 数 类 型 、 浮 点 类 型 或 一 个 针 对 对 象 的 指针 任何算术类型 |
||||||
一 个 针 对(void*) 函数指针 |
对 |
象 |
的 |
指 |
针 |
或 |
任 何 整 数 类 型 、 (void*) 、 一 个 针 对 对 象 的 指针或一个函数指针 任 何 整 数 类 型 、 一 个 针 对 对 象 的 指 针 或 一 个 函 |
数指针 |
一个结构、联合或数组 无
void 类型 任何类型
任 何 标 识 符 都 可 以 造 型 转 换 为 void, 但 如 果 在 一 个 类 型 造 型 表 达 中 的 指定 的 类 型 不 是 void ,那 么 该 标 识 符 造 型 转 换 成 不 是 一 个 void 表 达 式 的 类型 。 任 何 表 达 式 都 可 以 造 型 为 void ,但 一 个 类 型 为 void 的 类 型 不 能 造 型转 换 为 任 何 其 它 类 型 。 例 如 ,一 个 具 有 void 类 型 的 函 数 不 能 有 另 一 个 类型 的 返 回 值 。
注 意 , 一 个 void 表 达 式 有 一 个 void 的 类 型 指 针 ,而 不 是 类 型 void 。 如 果一 个 对 象 类 型 为 void 类 型 , 其 结 果 表 达 式 不 能 赋 给 任 何 项 。 类 似 地 ,一 个类 型 造 型 对 象 不 是 一 个 可 接 受 的 l 值 ,因 此 不 能 赋 给 一 个 类 型 造 型 对 象 。Microsoft 特 殊 处 →
只 要 该 标 识 符 的 尺 寸 不 发 生 改 变 ,一 个 类 型 造 型 可 以 是 一 个 l 值 表 达 式 。有 关 l 值 表 示 式 的 信 息 ,参 见 本 章 开 头 的 “ L 值 和 R 值 表 达 式 ”。
Microsoft 特 殊 处 结 束
你 可 以 用 一 个 造 型 把 一 个 表 达 式 转 换 为 类 型 void, 但 结 果 表 达 式 只 能 用于 不 需 要 一 个 值 的 地 方 。 一 个 转 换 为 void * 的 对 象 指 针 ,在 回 过 来 转 换 为最 初 的 类 型 时 将 返 回 它 的 最 初 值 。
函 数 调 用 转 换
在 一 个 函 数 调 用 中 参 量 上 执 行 的 转 换 类 型 依 赖 于 用 于 说 明 该 被 调 用 函 数的 参 量 的 函 数 原 型 ( 向 前 说 明 )。
如 果 有 一 个 函 数 原 型 上 包 括 说 明 的 参 量 类 型 , 编 译 器 执 行 类 型 检 测 ( 参 见第 6 章 “ 函 数 ” )。
如 果 没 有 函 数 原 型 , 则 在 函 数 调 用 中 参 量 上 执 行 常 用 的 算 术 转 换 。 这 些转 换 在 调 用 中 的 每 个 参 量 上 独 立 执 行 。 这 意 味 着 一 个 float 值 可 以 转 换为 一 个 double 值 ;一 个 char 或 short 值 可 以 转 换 为 一 个 in t;一 个 unsigned char 或 unsigned sort 可 以 转 换 为 一 个 unsigned in t。
第 5 章 语 句
一 个 C 程 序 的 语 句 控 制 一 个 程 序 执 行 的 流 程 。 在 C 中 ,和 其 它 程 序 设 计语 言 中 一 样 , 有 几 种 类 型 的 语 句 可 以 用 来 执 行 循 环 、 选 择 其 它 执 行 的 语句 以 及 转 换 控 制 。 后 面 简 要 概 述 语 句 语 法 , 本 章 以 字 母 排 序 次 序 描 述 这些 C 语 句 :
break 语句 if 语句
复合语句 空语句
continue 语句 return 语句
do-while 语句 switch 语句
表达式语句 try-except 语句
for 语句 try-finally 语句
goto 和标号语句 while 语句
语 句 概 述
C 语 句 由 语 句 符 号 、 表 达 式 和 其 它 语 句 组 成 。 一 个 构 成 另 一 个 语 句 的 组成 成 分 的 语 句 被 称 为 “ 体 ”。 本 章 讨 论 了 如 下 语 法 给 出 的 每 种 语 句 类 型 。语法
语句 :
标号语句 复合语句 表达式语句选择语句 迭代语句 跳转语句
try-except 语句 /* M icrosoft 特殊处 */ try_finally 语句 /* Microsoft 特殊处 */
语 句 体 频 繁 地 是 作 为 “ 复 合 语 句 ” , 一 个 复 合 语 句 由 其 它 包 括 关 键 字 的
语 句 组 成 。 复 合 语 句 通 过 花 括 号 ({}) 限 定 。 所 有 其 它 C 语 句 以 一 个 分 号
(;) 结 尾 。 一 个 分 号 是 一 个 语 句 结 束 符 。
表 达 式 语 句 包 含 一 个 C 表 达 式 ,该 C 表 达 式 包 含 第 4 章 “ 表 达 式 和 赋 值 ” 中 介 绍 的 算 术 和 逻 辑 运 算 符 。 null 语 句 是 一 个 空 语 句 。
任 何 C 语 句 可 以 以 一 个 标 识 的 标 号 开 头 ,该 标 号 由 一 个 名 称 加 一 个 冒 号组 成 。 由 于 只 有 goto 语 句 识 别 语 句 标 号 ,语 句 标 号 与 goto 一 起 讨 论 ,有 关更 多 信 息 参 见 本 章 后 面 的 “ goto 和 标 号 语 句 ”。
break 语 句
break 语 句 用 于 终 止 包 含 它 的 do 、 for、 switch 或 while 语 句 的 执 行 。 控制 传 递 给 该 终 止 语 句 的 后 续 语 句 。
语法
跳转语句 :
break;
break 语 句 频 繁 地 使 用 在 一 个 switch 语 句 中 以 终 止 一 个 特 殊 情 况 的 处理 。 缺 少 包 含 它 的 迭 代 语 句 或 switch 语 句 时 产 生 一 个 错 误 。
在 嵌 套 的 语 句 中 ,break 语 句 仅 终 止 直 接 包 含 它 的 do 、for、switch 或 while
语 句 。
你 可 以 使 用 一 个 return 或 goto 语 句 把 控 制 转 向 该 嵌 套 结 构 的 外 面 的 地方 。
如 下 例 子 说 明 了 break 语 句 :
for (i=0,i<LENGTH;i++) /* 当执行 break 语句时控制返回到这里 */
{
for(j=0,j<WIDTH;j++)
{
if (lins[i][j]==′ \0 ′ )
{
lengths[i]=j; break;
}
}
}
这 个 例 子 处 理 一 个 存 储 在 lines 中 的 可 变 长 度 字 符 串 的 数 组 。 break 语 句
导 致 在 每 个 字 符 串 中 找 到 结 尾 的 空 格 字 符 ( ′ \0 ′ ) 后 退 出 里 层 的 for 循环 并 把 该 位 置 存 储 在 lengths[i] 中 。
在 break 导 致 从 里 层 循 环 退 出 时 变 量 j 不 增 大 。 然 后 控 制 返 回 到 外 层 for
循 环 。 i 增 大 且 重 复 这 个 过 程 直 到 i 大 于 或 等 于 LENGTH 。
复 合 语 句
一 个 复 合 语 句 ( 也 称 为 一 个 “ 块 ” ) 一 般 作 为 另 一 语 句 例 如 if 语 句 的 语 句体 出 现 。 第 3 章 “ 说 明 和 类 型 ” 描 述 了 出 现 在 一 个 复 合 语 句 开 头 的 说 明的 格 式 和 含 义 。
语法
复合语句 :
{ 说明表 opt 语句表 opt }
说明表 :
说明
说明表 说明语句表 :
语句
语句表 语句
如 果 有 说 明 , 它 们 必 须 放 在 任 何 语 句 之 前 。 每 个 在 一 个 复 合 语 句 开 头 说明 的 标 识 符 的 范 围 从 其 说 明 点 开 始 延 伸 到 该 块 结 束 。 它 在 该 块 中 是 可 见的 ,除 非 在 一 个 更 里 层 的 块 中 存 在 相 同 名 称 的 标 识 符 的 说 明 。
在 一 个 复 合 语 句 中 的 标 识 符 都 假 定 是 auto ,除 非 用 register、static 或 extern 进 行 显 式 说 明 , 除 了 函 数 之 外 , 因 为 函 数 只 能 是 extern 。 你 可 以 在 函 数 说明 中 省 略 extern 指 示 符 , 该 函 数 仍 然 是 extern 的 。
如 果 一 个 变 量 或 函 数 在 一 个 复 合 语 句 中 用 存 储 类 extern 说 明 ,则 不 分 配存 储 , 不 能 进 行 初 始 化 。 该 说 明 指 的 是 在 其 它 地 方 定 义 的 一 个 外 部 变 量或 函 数 。
在 一 个 块 中 用 auto 或 register 关 键 字 说 明 的 变 量 被 重 新 说 明 , 如 果 必 要 , 在 每 次 进 入 该 复 合 语 句 时 进 行 初 始 化 。 这 些 变 量 在 该 复 合 语 句 退 出 时 就没 有 定 义 了 。 如 果 一 个 变 量 在 一 个 块 内 说 明 并 具 有 static 属性 , 在 程 序 执行 开 始 时 初 始 化 该 变 量 并 在 整 个 程 序 中 保 存 它 的 值 。 有 关 static 的 信 息参 见 第 3 章 “ 说 明 和 类 型 ” 中 的 “ 存 储 类 ”。
这 个 例 子 说 明 一 个 复 合 语 句 :
if (i>0)
{
line[i]=x; x ++ ;
i--;
}
在 这 个 例 子 中 , 如 果 i 大于 0 ,那 么 该 复 合 语 句 中 的 所 有 语 句 依 次 执 行 。
continue 语 句
continue 语 句 把 控 制 传 递 给 包 含 该 语 句 的 do 、 for 或 while 语 句 的 下 一 次迭 代 , 绕 过 do 、 for 或 while 语 句 体 的 任 何 余 下 语 句 。 continue 的 一 般 使用 是 从 一 个 深 的 嵌 套 循 环 中 返 回 到 一 个 循 环 的 开 头 。
语法
跳转语句 :
continue;
确 定 一 个 do 、 for 或 while 语 句 的 下 一 次 迭 代 如 下 :
-
在 一 个 do 或 一 个 while 语 句 中 , 通 过 重 新 do 或 while 语 句 中 表 达式 的 求 值 来 开 始 下 一 次 迭 代 。
-
在 一 个 for 语 句 中 的 continue 语 句 导 致 for 语 句 的 第 一 个 表 达 式被 求 值 , 然 后 编 译 器 重 新 条 件 表 达 式 的 求 值 , 根 据 其 结 果 , 终 止 或 迭代 该 语 句 体 。 有 关 for 语 句 和 它 的 非 终 结 符 的 更 多 信 息 参 见 本 章 后面 的 “ for 语 句 ”。
如 下 是 continue 语 句 的 例 子 :
while(i-->0)
{
x=f(i); if(x==1)
continue; y+=x*x;
}
在 这 个 例 子 中 , 当 i 大 于 0 时 执 行 该 语 句 体 。 首 先 把 f(i)赋 给 x, 然 后 如 果x 等 于 1, 则 执 行 continue 语 句 , 忽 略 语 句 体 中 其 余 的 语 句 ,执 行 回 到 该 循环 的 顶 部 ,求 值 该 循 环 的 测 试 。
do-while 语 句
do-while 语 句 让 你 重 复 一 个 语 句 或 复 合 语 句 直 到 一 个 指 定 的 条 件 变 成假 。
语法
迭代语句 :
do 语句 while( 表达式 );
在 一 个 do-while 语 句 中 的 表 达 式 在 执 行 该 循 环 体 之 后 求 值 ,因 此 该 循 环体 至 少 执 行 一 次 。
该 表 达 式 必 须 是 算 术 或 指 针 类 型 。 执 行 过 程 如 下 :
-
执行语句体。
-
接着对表达式求值 ,如果该表达式为假 ,该 do-while 语句终止
,控制转向程序中的下一个语句 , 如果表达式为真 ( 非 0), 重复该过程 ,从第 1 步开始。
当执行语句体中的一个 break 、 goto 或 return 语句时也终止该 do-while 语句。如下是 do-while 语句的例子 :
do
{
y=f(x);
x--;
} while(x>0);
在 这 个 do-while 语 句 中 ,执 行 y=f(x) ;和 x--;两 个 语 句 , 不 论 x 的 初 值 如 何 。然 后 求 值 x>0 ,如 果 x 大 于 0 ,则 又 执 行 该 语 句 体 和 重 新 求 值 x>0, 只 要 x 保 持 大 于 0 ,则 重 复 执 行 该 语 句 体 。当 x 变 成 0 或 负 数 时 终 止 该 do-while 语 句 的 执 行 ,该 循 环 体 至 少 执 行 一 次 。
表 达 式 语 句
当 执 行 一 个 表 达 式 语 句 时 , 根 据 第 4 章 “ 表 达 式 和 赋 值 ” 中 给 出 的 规 则对 该 表 达 式 求 值 。
语法
表达式语句 :
表达式 opt
一 个 表 达 式 求 值 的 所 有 副 作 用 都 在 执 行 下 一 个 语 句 之 前 完 成 。 一 个 空 表
达 式 语 句 称 为 一 个 空 语 句 。 有 关 更 多 信 息 参 见 本 章 后 面 的 “ 空 语 句 ”。这 些 例 子 说 明 了 表 达 式 语 句 :
x=(y+3); /* 把 y+3 的值赋给 x*/
x++; /*x 增 1*/
x=y=0 /* 把 x 和 y 都初始化为 0 */ proc(arg1,arg2); /* 函 数 调 用 返 回 void */
y=z=(f(x)+3); /* 一个函数调用表达式 */
在 最 后 一 个 函 数 调 用 表 达 式 语 句 中 , 该 表 达 式 的 值 包 括 该 函 数 返 回 的 任何 值 再 增 大 3 ,然 后 赋 给 变 量 y 和 z 。
for 语 句
for 语 句 让 你 重 复 一 个 语 句 或 复 合 语 句 指 定 的 次 数 。 一 个 for 语 句 体 执 行
0 次 或 多 次 直 到 一 个 任 选 的 条 件 变 成 假 。 你 可 以 在 for 语 句 中 使 用 任 选表 达 式 并 在 for 结 构 的 执 行 中 初 始 化 和 改 变 值 。
语法
迭代语句 :
for (初始表达式 opt ;条件表达式 opt;循环表达式 opt ) 语句
- 个 for 语 句 的 执 行 过 程 如 下 :
-
如 果 有 ,则 求 值 初 始 表 达 式 , 这 指 出 该 循 环 的 初 始 化 。 初 始 表 达 式 在 类型 上 没 有 限 制 。
-
如 果 有 ,则 求 值 条 件 表 达 式 , 这 个 表 达 式 必 须 是 算 术 或 指 针 类 型 。 它 在每 次 迭 代 之 前 求 值 , 有 三 种 可 能 的 结 果 :
-
如 果 条 件 表 达 式 为 真 ( 非 0), 则 执 行 该 语 句 。然 后 如 果 有 循 环 表 达 式 , 则 对 其 求 值 。 在 每 次 迭 代 之 后 都 对 循 环 表 达 式 求 值 。 其 类 型 没 有 限制 。 副 作 用 将 依 次 执 行 。 然 后 又 开 始 求 值 条 件 表 达 式 的 过 程 。
-
如 果 省 略 了 条 件 表 达 式 , 条 件 表 达 式 被 认 为 是 真 , 执 行 过 程 和 前 面 段中 描 述 的 过 程 完 全 一 样 。 一 个 没 有 条 件 表 达 式 的 for 语 句 仅 在 执 行
语 句 体 中 的 break 或 return 语 句 时 终 止 , 或 者 在 执 行 一 个 ( 跳 出 for 语 句 体 )goto 语 句 时 终 止 。
- 如 果 条 件 表 达 式 为 假 (0),for 语 句 的 执 行 终 止 , 并 把 控 制 传 递 给 程 序中 的 下 一 个 语 句 。
- 个 for 语 句 也 在 执 行 语 句 体 中 的 break 、 goto 或 return 语 句 时 终 止 。 一个 for 循 环 中 的 continue 语 句 导 致 求 值 循 环 表 达 式 。 当 执 行 一 个 for 循环 中 的 break 语 句 时 , 循 环 表 达 式 不 求 值 或 执 行 。 如 下 语 句 :
for(;;);
是 一 个 通 常 的 产 生 无 限 循 环 的 方 式 ,它 只 能 用 break 、 goto 或 return 语 句退 出 。
如 下 例 子 说 明 for 语 句 :
for(i=space=tab=0;i<MAX,i++)
if (line[i]== ′′ ) space++;
if (line[i]== ′ \t′ )
{
tab++; line[i]= ′′ ;
}
}
这 个 例 子 对 名 称 为 line 的 字 符 数 组 中 的 空 格 (′′ ) 和 制 表 键 (′ \t′ ) 进 行 计
数 ,并 用 一 个 空 格 替 换 每 个 制 表 键 , 首 先 i、 space 和 tab 都 初 始 化 为 0 。 然后 i 和 常 量 M A X 进 行 比 较 ;如 果 i 小 于 M A X ,则 执 行 该 语 句 体 。根 据 line[i] 的 值 , 执 行 或 不 执 行 if 语 句 的 语 句 体 。 然 后 i 增 1 并 又 与 M A X 比 较 , 只要 i 小于 M A X 则 重 复 地 执 行 该 语 句 体 。
goto 和 标 号 语 句
goto 语 句 转 换 控 制 到 一 个 标 号 。 给 定 的 标 号 必 须 在 相 同 的 函 数 中 , 而 且只 能 出 现 在 相 同 函 数 中 的 一 个 语 句 的 前 面 。
语法语句 :
标号语句跳转语句
跳转语句 :
goto 标识符标号语句 :
标识符 :语句
-
个 语 句 标 号 仅 对 goto 语 句 有 意 义 , 在 任 何 其 它 上 下 文 中 ,一 个 标 号 语 句的 执 行 忽 略 该 标 号 。
-
个 跳 转 语 句 必 须 保 留 在 相 同 的 函 数 中 , 只 能 出 现 在 相 同 函 数 中 一 个 语句 之 前 。 跟 随 一 个 goto 的 标 识 符 名 称 有 它 自 己 的 名 称 空 间 ,因 此 该 名 称与 其 它 标 识 符 无 关 。 标 号 不 能 重 新 说 明 。 有 关 更 多 信 息 参 见 第 2 章 “ 程
序 结 构 ” 中 的 “ 名 称 空 间 ”。
- 种 好 的 程 序 设 计 风 格 是 在 可 能 出 现 goto 的 地 方 优 先 使 用 break 、continue 和 return 语 句 。 一 个 break 语 句 只 能 从 一 个 循 环 层 退 出 ,而 一 个goto 可 以 从 深 的 嵌 套 循 环 中 退 出 。
如 下 例 子 说 明 了 goto 语 句 的 作 用 :
void main()
{
int i,j;
for (i=0,i<10;i++)
{
printf("Outer loop executing. i=%d\n",i); for(j=0;j<3;j++)
{
printf("Inner loop executing. j=%d\n",j), if (i==5)
goto stop;
}
}
/* 这个消息不打印 */
printf ("Loop exited. i=%d\n",i); stop:printf("Jumped to stop,i=%d\n",i);
}
在这个例子中 , 在 i 等于 5 时一个 goto 语句把控制转向括号为 stop 的语句。
if 语 句
if 语 句 控 制 条 件 分 支 。如 果 其 中 表 达 式 的 值 为 非 0 则 执 行 一 个 if 语 句 体 ,if
语 句 的 语 法 有 两 种 格 式 。
语法
选择语句 :
if ( 表达式 ) 语句
if ( 表达式 ) 语句 else 语句
在 if 语 句 的 两 种 格 式 中 , 其 中 的 表 达 式 可 以 具 有 除 结 构 外 的 任 何 类 型 ,它被 求 值 , 包 括 所 有 副 作 用 。 在 语 法 的 第 一 种 格 式 中 , 如 果 表 达 式 为 真 ( 非 0), 则 执 行 其 中 的 语 句 ; 如 果 该 表 达 式 为 假 (0), 则 忽 略 该 语 句 。 在 该 语 法 的 第二 种 格 式 中 , 它 使 用 了 else,如 果 表 达 式 的 值 为 假 , 则 执 行 第 二 个 语 句 。 使用 这 两 种 格 式 , 控 制 都 从 if 语 句 转 向 程 序 中 的 下 一 个 语 句 ,除 了 其 中 语 句之 一 包 含 一 个 break 、 continue 或 goto 之 外 。
如 下 是 if 语 句 的 例 子 :
if(i>0)
y=x/i; else
{
x=i; y=f(x);
}
在 这 个 例 子 中 , 如 果 i 大 于 0 则 执 行 y=x/i; 语 句 ;如 果 i 小 于 或 等 于 0, 则 把
i 赋 给 x, 且 把 f(x )赋 给 y 。 注 意 形 成 if 子 句 的 语 句 以 一 个 分 号 结 尾 。
当 嵌 套 if 语 句 和 else 子 句 时 ,使 用 花 括 号 来 组 合 语 句 。 形 成 一 个 更 清 楚的 复 合 语 句 。 如 果 不 出 现 在 括 号 , 编 译 器 通 过 把 else 与 最 近 的 缺 少 else 的 if 进 行 关 联 来 解 决 模 糊 性 。
if (i>0) /* 没 有 花 括 号 */ if(j>i)
x=j;
else
x=i;
在 这 个 例 子 中 ,else 子 句 与 里 层 的 if 语 句 关 联 。 如 果 i 小 于 或 等 于 0 ,则 没有 值 赋 给 x 。
if (i>0)
{ /* 有花括号 */ if (j>i)
x=j;
}
else
x=j;
在 这 个 例 子 中 里 层 的 if 语 句 用 花 括 号 括 起 来 , 使 else 子 句 与 外 层 if 语 句匹 配 。 如 果 i 小 于 或 等 于 0, 把 i 赋 给 x 。
空 语 句
一 个 “ 空 语 句 ” 是 一 个 仅 包 含 分 号 的 语 句 。 它 可 以 出 现 在 一 个 语 句 能 够出 现 的 任 何 地 方 。
当 执 行 一 个 空 语 句 时 不 发 生 任 何 事 件 。 编 写 一 个 空 语 句 的 正 确 方 式 是 :
语 法
;
例 如 do 、 for、 if 和 while 语 句 需 要 一 个 可 执 行 的 语 句 出 现 在 其 语 句 体 中 ,
在 不 需 要 一 个 实 际 的 语 句 体 的 情 况 下 要 求 空 语 句 满 足 语 法 要 求 。
正 如 其 它 任 何 C 语 言 一 样 。 你 可 以 在 一 个 空 语 句 之 前 包 括 一 个 标 号 。为 了 给 一 个 不 是 语 句 的 项 加 上 标 号 时 , 例 如 一 个 复 合 语 句 的 闭 花 括 号 , 你可 以 给 一 个 空 语 句 加 上 标 号 , 把 它 直 接 插 入 到 获 得 相 同 效 果 的 项 之 前 。 这 个 例 子 说 明 了 空 语 句 的 作 用 :
for (i=0;i<10;ling[i++]=0)
;
在 这 个 例 子 中 ,for 语 句 的 循 环 表 达 式 line[i++]=0 初 始 化 line 的 开 头 10
个 元 素 为 0, 该 语 句 作 为 空 语 句 ,不 必 须 有 后 续 语 句 。
return 语 句
return 语 句 终 止 一 个 函 数 的 执 行 并 将 控 制 返 回 调 用 函 数 。 在 调 用 函 数 中该 调 用 点 之 后 恢 复 执 行 。 一 个 return 语 句 也 返 回 一 个 值 给 调 用 函 数 , 有关 更 多 信 息 参 见 第 6 章 “ 函 数 ” 中 的 “ 返 回 类 型 ”。
语 法
跳 转 语 法
return 表 达 式 opt
如 果 出 现 表 达 式 , 则 把 该 表 达 式 的 值 返 回 给 调 用 函 数 ; 如 果 省 略 该 表 达 式 , 该 函 数 的 返 回 值 是 不 确 定 的 。 如 果 出 现 表 达 式 , 该 表 达 式 转 换 成 函 数 返回 的 类 型 。 如 果 该 函 数 用 返 回 类 型 void 说 明 , 一 个 包 含 表 达 式 的 return 语 句 产 生 一 个 警 告 并 不 对 该 表 达 式 求 值 。
如 果 一 个 函 数 定 义 中 没 有 return 语 句 出 现 , 在 被 调 用 函 数 的 最 后 一 个 语句 执 行 之 后 控 制 自 动 返 回 给 调 用 函 数 , 在 这 种 情 况 下 , 被 调 用 函 数 的 返 回值 是 不 确 定 的 。 如 果 不 需 要 返 回 值 ,说 明 该 函 数 具 有 void 返 回 类 型 ;否 则 , 缺 省 的 返 回 类 型 是 in t。
很 多 程 序 员 使 用 圆 括 号 括 起 该 return 语 句 的 表 达 式 参 量 。 但 C 不 需 要 圆括 号 。 这 个 例 子 说 明 return 语 句 的 作 用 :
void draw(int I,long L); long sq(int s);
int main()
{
long y; int x;
y=sq(x);
draw(x,y);
return();
}
long sq(int s)
{
return (s * s);
}
void draw( int I, long L)
{
/* 这里的语句定义画图功能 */ return;
}
在 这 个 例 子 中 ,main 函 数 调 用 两 个 函 数 :sq 和 draw 。 sq 函 数 返 回 x*x 的值 到 main, 这 里 的 返 回 值 赋 给 y 。 draw 函 数 说 明 为 一 个 void 函 数 ,并 不 返回 值 。 试 图 赋 给 draw 返 回 值 会 导 致 发 生 一 个 诊 断 消 息 。
sw itch 语 句
switch 和 case 语 句 帮 助 控 制 复 杂 条 件 和 分 支 操 作 。 switch 语 句 把 控 制 转向 该 语 句 体 中 的 一 个 语 句 。
语 法
选 择 语 句 :
switch( 表 达 式 ) 语 句标 号 语 句 :
case 常 量 表 达 式 : 语句
default: 语 句
控 制 转 向 与 switch( 表 达 式 ) 的 值 匹 配 的 case 常 量 表 达 式 的 语 句 。 switch 语 句 可 以 包 含 任 何 个 数 的 case 实 例 , 但 在 同 一 个 switch 语 句 中 不 能 有 两个 switch 常 量 具 有 相 同 的 值 。 语 句 体 的 执 行 开 始 于 选 择 的 语 句 并 继 续执 行 直 到 该 语 句 体 结 束 或 者 直 到 一 个 break 语 句 转 移 控 制 到 该 语 句 体 之外 。
switch 语 句 的 使 用 通 常 象 这 样 的 :
switch( 表达式 )
{
说明
.
.
.
case 常量表达式
如果表达式等于这个常量表达式的值而执行的语句
.
.
.
break default:
如 果 表 达 式 " 不 等 于 任 何 情 况 常 量 表 达 式 时 而 执 行 的 语 句 "
}
你 可 以 使 用 break 语 句 终 止 switch 语 句 中 一 个 特 殊 情 况 的 处 理 并 跳 转 到该 switch 语 句 的 末 尾 ,没 有 break, 该 执 行 继 续 到 下 一 个 case, 执 行 语 句 直到 一 个 break 或 到 达 该 语 句 末 尾 , 在 有 些 情 况 下 ,这 个 继 续 是 希 望 的 。
如 果 没 有 case 常 量 表 达 式 等 于 switch( 表 达 式 ) 的 值 ,则 执 行 default 语 句 。如 果 省 略 了 default 语 句 且 没 有 case 匹 配 ,则 不 执 行 switch 体 中 的 语 句 。最 多 只 能 有 一 个 default 语 句 ,default 语 句 不 一 定 放 在 最 后 , 可 以 放 在switch 语 句 体 的 任 何 地 方 。 实 际 上 ,经 常 放 在 switch 语 句 开 头 更 有 效 。一 个 case 或 default 标 号 只 能 出 现 在 一 个 switch 语 句 内 部 。
switch 表 达 式 和 case 常 量 表 达 式 的 类 型 必 须 是 整 数 。 每 个 case 常 量 表达 式 的 值 在 语 句 体 中 必 须 是 唯 一 的 。
switch 语 句 体 的 case 和 default 标 号 仅 在 最 初 测 试 用 于 确 定 该 语 句 体 的执 行 开 始 的 位 置 。
switch 语 句 可 以 嵌 套 , 在 执 行 转 向 任 何 switch 语 句 之 前 初 始 化 任 何 静 态
变 量 。
注 意 : 说 明 可 以 出 现 在 该 复 合 语 句 的 开 头 形 成 switch 体 , 但 不 执 行包 括 在 说 明 中 的 初 始 化 。 switch 语 句 把 控 制 直 接 转 向 该 语 句 体 中 一 个可 执 行 的 语 句 , 绕 过 包 含 初 始 化 的 行 。
如 下 例 子 说 明 了 switch 语 句 的 作 用 :
switch (c)
{
case ′ A ′ : capa++;
case ′ a′ :
lettera++; default:
total++;
}
本 例 中 switch 体 的 所 有 三 个 语 句 在 c 等 于 ′ A ′ 时 都 执 行 ,因 为 在 每 个 case 之 前 没 有 出 现 一 个 break 语 句 。 执 行 控 制 转 向 第 一 个 语 句 (capa++), 并 继续 依 次 通 过 语 句 体 中 余 下 的 语 句 。 如 果 c 等 于 ′ A ′ ,则 lettera 和 total 都增 1 。 如 果 c 不 等 于 ′ A ′ 或 ′ a ′ ,则 只 有 total 增 1 。
switch(i)
{
case -1:
n++;
break; case 0:
z++;
break; case 1:
p++;
break;
}
在 这 个 例 子 中 ,switch 体 中 每 个 语 句 后 跟 一 个 break 语 句 。 break 语 句 在执 行 一 个 语 句 后 强 制 从 该 语 句 体 退 出 。如 果 i 等 于 -1 ,只 有 n 增 1 ,跟 随 n++ 语 句 后 面 的 break 语 句 导 致 执 行 控 制 转 出 该 语 句 体 , 而 避 开 其 余 的 语 句 。类 似 地 , 如果 i 等 于 0, 只 有 z 增 1 ; 如 果 i 等 于 1 , 只 有 p 增 1 。 最 后 的 一 个break 语 句 不 必 要 求 , 因 为 控 制 在 复 合 语 句 的 末 尾 就 转 出 体 外 , 但 为 了 一 致性 包 括 了 该 语 句 。
单 个 语 句 可 以 加 上 多 个 case 标号 , 正 如 如 下 例 子 :
case ′ a ′ :
case ′ b ′ :
case ′ c ′ :
case ′ d ′ :
case ′ e ′ :
case ′ f ′ :hexcvt(c);
在 这 个 例 子 中 , 如 果 常 量 表 达 式 等 于 ′ a ′ 到 ′ f ′ 的 任 何 字 母 , 则 调 用
hexcvt 函 数 。
Microsoft 特 殊 处 →
Microsoft C 不 限 制 一 个 switch 语 句 中 case 子 句 的 个 数 ,其 个 数 仅 受 限 于可 用 的 存 储 器 。
ANSI C 在 一 个 switch 语 句 至 多 允 许 257 个 case 标 号 。
Microsoft C 缺 省 能 使 M icrosoft 扩 充 ,使 用 /Za 编 译 器 选 项 禁 止 这 些 扩 充 。
Microsoft 特 殊 处 结 束
try-except 语 句
Microsoft 特 殊 处 →
try-except 语 句 是 C 语 言 的 M icrosoft 扩 充 ,它 能 使 一 个 应 用 在 出 现 正 常终 止 执 行 事 件 时 获 取 程 序 控 制 , 这 样 的 事 件 称 为 异 常 , 处 理 异 常 的 机 制 被称 为 结 构 的 异 常 处 理 。
异 常 可 以 基 于 硬 件 或 基 于 软 件 的 , 甚 至 在 应 用 不 能 从 硬 件 或 软 件 异 常 完全 恢 复 时 , 结 构 的 异 常 处 理 使 它 可 能 显 示 错 误 信 息 并 捕 捉 该 应 用 的 内 部状 态 帮 助 诊 断 新 问 题 。 这 对 于 处 理 不 容 易 重 现 的 间 歇 性 问 题 特 别 有 用 。
语法
try-except 语句 :
__ try 复合语句
__ except( 表达式 ) 复合语句
在 __ try 语 句 之 后 的 复 合 语 句 是 保 护 段 。 _ _except 子 句 之 后 的 复 合 语 句 是
异 常 处 理 器 。 该 处 理 器 指 出 在 保 护 段 执 行 期 间 发 生 一 个 异 常 时 所 执 行 的一 组 动 作 。 执 行 过 程 如 下 :
-
执 行 保 护 段 。
-
如 果 在 保 护 段 执 行 期 间 没 有 异 常 发 生 ,继 续 执 行
__ except 子 句 之 后 的 语句 。
-
如 果 在 保 护 段 执 行 期 间 出 现 一 个 异 常 或 者 在 保 护 段 调
用 的 例 程 中 出现 一 个 异 常 ,则 __except 表 达 式 被 求 值 , 其 返 回 值 确 定 如 何 处 理 异 常 。 这 里有 三 个 值 :
EXCEPTION_CONTINUE_SEARCH : 异 常 不 能 识 别 , 继 续 搜 索 栈 查 找 一个 处 理 器 ,首 先 搜 索 包 含 try-except 语 句 的 处 理 器 , 然 后 搜 索 下 一 个 最 高 优先 级 的 处 理 器 。
EXCEPTION_CONTINUE_EXECUTION :异 常 被 识 别 但 不 予 考 虑 。 继 续在 出 现 异 常 的 点 执 行 。
EXCEPTION_EXECUTE_HANDLER : 异 常 被 识 别 。 通 过 执 行 __ except 复合 语 句 把 控 制 转 向 异 常 处 理 器 , 然 后 在 出 现 异 常 的 点 继 续 执 行 。 因 为
__ except 表 达 式 作 为 一 个 C 异 常 被 求 值 , 它 限 制 为 单 个 值 、 条 件 表 达 式 运算 符 或 逗 号 运 算 符 。 如 果 需 要 更 广 泛 的 处 理 , 该 表 达 式 可 以 调 用 一 个 例程 返 回 上 述 所 列 的 三 个 值 之 一 。
注 意 : 结 构 的 异 常 处 理 与 C 和 C++ 源 文 件 一 起 工 作 。 虽 然 它 不 能 特 别为 C++ 设计 , 你 能 够 通 过 使 用 C++ 异 常 处 理 确 保 你 的 代 码 具 有 更 好 的 移 植性 。 C++ 异 常 处 理 机 制 也 具 有 更 好 的 灵 活 性 , 它 能 够 处 理 任 何 类 型 的 异常。
对 于 C++ 程 序 ,C++ 异 常 处 理 可 以 用 于 代 替 结 构 的 异 常 处 理 。 有 关 更多 信 息 , 参 见 本 书 后 面 “ Microsoft Vis u al C++6.0 语 言 参 考 手 册 ” 部分第 5 章 “ 语 句 ” 中 的 “ 异 常 处 理 ”。
一 个 应 用 中 的 每 个 例 程 都 有 自 己 的 异 常 处 理 器 。 __except 表 达 式 在 __try
语 句 体 的 范 围 内 执 行 。 这 意 味 着 它 可 以 访 问 这 里 说 明 的 任 何 局 部 变 量 。
__ leave 关 键 字 在 一 个 try-except 语 句 块 中 是 有 效 的 。 _ _leave 的 作 用 是 跳
到 该 try-except 块 的 末 尾 。 在 该 异 常 处 理 器 结 束 之 后 恢 复 执 行 。 虽 然 一个 goto 语 句 可 以 用 于 完 成 同 样 的 功 能 ,但 一 个 goto 语 句 导 致 栈 的 消 除 内务 操 作 。
__ leave 语 句 更 有 效 , 因 为 它 不 涉 及 到 栈 的 消 除 内 务 操 作 。
使 用 longjmp 运 行 函 数 退 出 一 个 try-except 语 句 认 为 是 异 常 终 止 。 跳 进
- 个 __ try 语 句 是 非 法 的 ,但 跳 出 一 个
_ _try 语 句 是 合 法 的 。 如 果 一 个 进 程
在 执 行 一 个 try-except 语 句 中 被 删 除 则 不 调 用 该 异 常 处 理 器 。例 子
如 下 是 一 个 异 常 处 理 器 和 一 个 终 止 处 理 器 的 例 子 。 有 关 终 止 处 理 器 的 更多 信 息 参 见 下 一 节 “ try-finally 语 句 ”。
.
.
.
puts("hello");
__ try {
puts("in try");
__ try { puts("in try");
RAISE_AN_EXCEPTION();
} __ finally {
puts("in finally");
}
} __ except(puts("in filter"), EXCEPTION_EXECUTE_HANDLER) { puts("in except");
}
puts("world");
如下是上例的输出结果 , 在右边加有注释 : hello
in try /* 进入 try */
in try /* 进入嵌套的 try*/
in filter /* 执行过滤器 ;因此接受返回 1 */ in finally /* 消除嵌套的 finally*/
in except /* 转移控制到选择的处理器 */
world /* 退出处理器 */ M icrosoft 特殊处结束
try-finally 语 句
Microsoft 特 殊 处 →
try-finally 语 句 是 C 语 句 的 M icrosoft 扩 充 ,能 使 应 用 保 证 在 执 行 一 个 代码 块 中 断 时 执 行 清 理 (cleanup) 代 码 。 清 理 由 这 样 的 功 能 组 成 ,如 取 消 存 储器 分 配 关 闭 文 件 和 释 放 文 件 句 柄 。 try-finally 语 句 对 于 这 样 的 例 程 特 别有 用 , 该 例 程 有 几 个 位 置 检 测 导 致 过 早 地 从 该 例 程 返 回 的 错 误 。
语 法
try-finally 语 句 :
__ try 复 合 语 句
__ finally 复 合 语 句
__ try 子 句 后 的 复 合 语 句 是 保 护 段 。 _ _finally 子 句 后 的 复 合 语 句 是 终 止 处
理 器 。 该 处 理 器 指 出 在 退 出 保 护 段 时 执 行 的 一 组 动 作 , 无 论 该 保 护 段 是由 异 常 ( 非 正 常 终 止 ) 或 由 标 准 下 行 ( 正 常 终 止 ) 退 出 的 。
通 过 简 单 的 顺 序 执 行 ( 下 行 ) 控 制 到 达 一 个 __try 语 句 。 当 控 制 进 入 该 _
语 句 时 , 它 关 联 的 处 理 器 变 成 活 动 的 。 执 行 过 程 如 下 :
-
执 行 保 护 段 。
-
调 用 终 止 处 理 器 。
_try
- 当 终 止 处 理 器 完 成 后 , 继 续 执 行 __finally 语
句 之 后 的 语 句 , 无 论 该 保 护段 如 何 终 止 ( 例如 , 经由 goto 语 句 转 出 保 护 段 外 面 或 至 由 一 个 return 语 句 ) 在 控 制 流 移 出 保 护 段 之 前 执 行 该 终 止 处 理 器 。
__ leave 关 键 字 在 一 个 try-finally 语 句 块 中 是 有 效 的 。 _ _leave 的 作 用 是 跳
转 到 该 try-finally 块 的 末 尾 ,直 接 执 行 该 终 止 处 理 器 , 虽 然 一 个 goto 语 句可 以 用 于 完 成 相 同 的 功 能 , 但 一 个 goto 语 句 导 致 栈 的 消 除 内 务 操 作 。 _
_leave 语 句 更 有 效 , 因 为 它 不 涉 及 到 栈 的 消 除 内 务 操 作 。
使 用 一 个 return 语 句 或 longjmp 运 行 函 数 退 出 一 个 try-finally 语 句 被 认为 是 非 正 常 终 止 。 跳 进 一 个 __ try 语 句 是 非 法 的 , 但 从 中 跳 转 出 来 是 合 法的 。从 启 动 点 到 目 的 之 间 所 有 活 动 的 __ finally 语 句 必 须 运 行 , 这 称 之 为“局部 展 开 ”。
如 果 在 执 行 try-finally 语 句 时 一 个 进 程 被 删 去 ,则 不 调 用 该 终 止 处 理 器 。
注 意 : 结 构 的 异 常 处 理 与 C 和 C++ 源 文 件 一 起 工 作 。 虽 然 它 不 能 特 别为 C++ 设计 , 你 能 够 通 过 使 用 C++ 异 常 处 理 确 保 你 的 代 码 具 有 更 好 的 移 植性 。 C++ 异 常 处 理 机 制 也 具 有 更 好 的 灵 活 性 , 它 能 够 处 理 任 何 类 型 的 异常。
对 于 C++ 程 序 ,C++ 异 常 处 理 可 以 用 于 代 替 结 构 的 异 常 处 理 。 有 关 更 多信 息 , 参 见 本 书“ Microsoft Vis u al C++ 6.0 语 言 参 考 手 册 ”部 分 第 5 章“ 语句 ” 中 的 “ 异 常 处 理 ”。
参 见 try-except 语 句 的 例 子 看 try-finally 语 句 是 如 何 工 作 的 。
Microsoft 特 殊 处 结 束
while 语 句
while 语 句 让 你 重 复 一 个 语 句 直 到 指 定 的 表 达 式 变 成 假 。语 法
迭 代 语 句 :
while( 表 达 式 ) 语 句
该 表 达 式 必 须 具 有 算 术 或 指 针 类 型 。 执 行 过 程 如 下 :
-
对 表 达 式 进 行 求 值 。
-
如 果 表 达 式 起 初 为 假 , 不 执 行 while 语 句 体 。 控 制 从
while 语 句 转 向 程序 中 的 下 一 个 语 句 。
如 果 表 达 式 为 真 ( 非 0), 执 行 语 句 体 并 从 第 1 步 开 始 重 复 这 一 过 程 。
当 执 行 该 语 句 体 中 的 一 个 break 、 goto 或 return 时 也 终 止 while 语 句 。使 用 continue 语 句 终 止 一 次 迭 代 而 不 退 出 while 循 环 ,continue 语 句 把 控制 转 向 while 语 句 的 下 一 次 迭 代 。
如 下 是 一 个 while 语 句 的 例 子 :
while(i>=0)
{
string1[i] = string2[i]; i--;
}
这 个 例 子 把 字 符 从 string2 拷 贝 到 string1 。如 果 i 大 于 或 等 于 0 ,把 string2[i] 赋 给 string[i] 并 将 i 减 1 。当 i 到 达 0 或 小 于 0 时 ,终 止 该 while 语 句 的 执行 。
第 6 章 函 数
函 数 是 C 中 的 基 本 模 块 单 元 。 一 个 函 数 设 计 用 于 执 行 特 定 的 功 能 , 它 的名 称 通 常 反 映 其 功 能 。 一 个 函 数 包 含 说 明 和 语 句 。 本 章 描 述 如 何 说 明 、定 义 和 调 用 函 数 的 。 其 它 讨 论 的 主 题 有 :
-
函 数 概 述
-
函 数 定 义
-
函 数 原 型
-
函 数 调 用
函 数 概 述
函 数 必 须 有 一 个 定 义 和 一 个 说 明 , 如 果 说 明 出 现 在 函 数 被 调 用 之 前 , 一 个定 义 可 以 作 为 一 个 说 明 , 函 数 定 义 包 括 函 数 体 即 在 该 函 数 被 调 用 时 执 行的 代 码 。
- 个 函 数 说 明 建 立 名 称 、 返 回 值 和 在 程 序 其 它 地 方 定 义 的 函 数 的 属 性 。一 个 函 数 说 明 必 须 位 于 该 函 数 调 用 的 前 面 。 这 是 为 什 么 在 你 的 代 码 中 调用 一 个 运 行 函 数 之 前 包 括 包 含 该 运 行 函 数 说 明 的 头 文 件 的 原 因 。 如 果 该说 明 具 有 类 型 和 参 数 个 数 的 信 息 ,该 说 明 是 原 型 。
有 关 更 多 信 息 参 见 本 章 后 面 的 “ 函 数 原 型 ”。
编 译 器 使 用 该 原 型 将 后 面 调 用 中 的 参 量 类 型 与 具 有 该 函 数 参 数 的 函 数 进行 比 较 , 必 要 时 把 参 量 类 型 转 换 成 参 数 的 类 型 。
- 个 函 数 调 用 将 执 行 控 制 从 调 用 函 数 传 递 到 被 调 用 函 数 。 如 果 有 参 量 , 参 量 通 过 被 调 用 函 数 的 值 传 递 。 在 被 调 用 函 数 中 执 行 一 个 return 语 句 返回 控 制 和 一 个 可 能 的 值 到 调 用 函 数 。
已 废 除 的 函 数 说 明 和 定 义 格 式
旧 式 函 数 说 明 和 定 义 使 用 在 说 明 参 数 上 有 点 不 同 于 ANSI C 标 准 推 荐 的语 法 。 首 先 ,旧 式 说 明 没 有 参 数 表 ;第 二 ,在 函 数 定 义 中 列 出 参 数 , 但 在 参 数表 中 不 说 明 它 们 的 定 义 。 类 型 说 明 位 于 组 成 该 函 数 体 的 复 合 语 句 的 前面 。 旧 式 语 法 已 废 除 了 , 不 在 新 代 码 中 使 用 。 但 仍 支 持 使 用 旧 式 语 法 的代 码 。 如 下 例 子 给 出 了 说 明 和 定 义 的 已 废 除 的 格 式 :
double old_style(); /* 已废除的函数说明 */
double alt_style(a,real) /* 已废除的函数说明 */ double *real;
int a;
{
return (*real+a);
}
返 回 一 个 整 数 或 与 一 个 int 具 有 相 同 尺 寸 的 指 针 的 函 数 不 需 要 有 一 个 说
明 ,虽 然 建 议 有 该 说 明 。
为 了 遵 守 ANSI C 标准 ,旧 式 函 数 说 明 使 用 一 种 省 略 方 式 , 现 在 使 用 /Za 选项 时 会 产 生 一 个 错 误 ;当 使 用 /Ze 选 项 时 产 生 一 个 第 4 层 的 警 告 。 例 如 : void funct l(a,...) /* 在 /Ze 下产生一个警告 */
int a; /* 或在 /Za 下产生一个错误 */
{
}
你可以作为原型重写这个说明 :
void funct1(int a,...)
{
}
如 果 你 在 后 面 用 一 个 省 略 或 一 个 不 同 于 其 提 升 类 型 的 类 型 参 数 来 说 明 或定 义 相 同 函 数 , 则 旧 式 函 数 说 明 也 产 生 警 告 。
下 一 节 “ 函 数 定 义 ” 说 明 了 函 数 定 义 的 语 法 , 包 括 旧 式 语 法 。 在 旧 式 语法 中 参 数 表 的 非 终 结 符 是 标 识 符 表 。
函 数 定 义
一 个 函 数 指 出 函 数 的 名 称 、 它 接 受 的 参 数 类 型 和 个 数 以 及 它 的 返 回 值 。一 个 函 数 定 义 还 包 括 说 明 它 的 局 部 变 量 以 及 确 定 该 函 数 所 做 事 情 的 函 数体 。
语法
转换单元 :
外部说明
转换单元 外部说明
外部说明 : /* 仅允许在外部 ( 文件 ) 范围内 */
函数定义说明
函数定义 : /* 这里的说明符是函数说明符 */
说明指示符 opt 属性序列 opt 说 明 符 说明表 opt 复合语句
/* 属性序列是 M icrosoft 特殊处 */
原型参数是 :
说明指示符 :
存储类指示符 说明指示符 opt 类型指示符 opt 类型指示符 说明指示符 opt
类型修饰符 说明指示符 opt
说明表 :
说明
说明表 说明说明符 :
指针 opt 直接说明符
直接说明符 : /* 一个函数说明符 */
直接说明符 ( 参数类型表 ) /* 新式说明符 */
直接说明符 ( 标识符表 opt ) /* 已废除的说明符 */
在 一 个 定 义 中 参 数 表 使 用 以 下 语 法 :
参数类型 : /* 参 数 表 */
参数表 参数表 ,...
参数表 :
参数说明
参数表 ,参数说明参数说明 :
参数指示符 说明符
说明指示符 抽象说明符 opt
在一个旧式函数定义中的参数表使用以下语法 :
标识符表 : /* 已废除的函数定义和说明 */
标识符
标识符表 ,标识符函数体的语法 :
复合语句 : /* 函 数 体 */
{ 说明表 opt 语 句 表 opt }
可 以 用 于 修 饰 一 个 函 数 说 明 的 存 储 类 指 示 符 只 有 extern 和 static 。 extern 指 示 符 指 示 该 函 数 可 以 从 其 它 文 件 引 用 , 也 就 是 , 该 函 数 名 称 被 输 出 到 链接 器 。 static 指 示 符 指 示 该 函 数 不 能 从 其 它 文 件 引 用 , 也 就 是 , 该 函 数 名 称不 输 出 到 链 接 器 。 如 果 一 个 函 数 定 义 中 不 出 现 存 储 类 ,则 假 设 是 extern 。在 任 何 情 况 下 , 该 函 数 从 定 义 点 到 文 件 结 尾 就 是 可 见 的 。
任 选 说 明 指 示 符 和 强 制 性 说 明 符 一 起 指 出 该 函 数 的 返 回 类 型 和 名 称 。 说
明 符 是 命 名 该 函 数 的 标 识 符 和 紧 跟 函 数 名 的 圆 括 号 的 组 合 。 传 送 的 属 性序 列 非 终 结 符 是 定 义 在 “ 函 数 属 性 ” 中 的 M icrosoft 特 殊 特 征 。
直 接 说 明 符 ( 在 说 明 符 语 法 中 ) 指 出 定 义 的 函 数 的 名 称 和 它 的 参 数 的 标 识符 。 如 果 直 接 说 明 符 包 括 一 个 参 数 表 , 该 表 指 出 所 有 参 数 的 类 型 。 这 样的 一 个 说 明 符 也 作 为 后 面 调 用 该 函 数 的 一 个 函 数 原 型 。
在 函 数 定 义 中 的 说 明 表 中 的 一 个 说 明 不 能 包 含 register 之 外 的 一 个 存 储类 指 示 符 。 只 有 在 为 一 个 int 类 型 的 值 指 定 register 存 储 类 时 ,其 说 明 指示 符 语 法 中 的 类 型 指 示 符 可 以 省 略 。
复 合 语 句 是 包 含 局 部 变 量 说 明 、 引 用 外 部 的 说 明 项 和 语 句 的 函 数 体 。“ 函 数 属 性 ”、“ 存 储 类 ”、“ 返 回 值 ”、“ 参 数 ” 和 “ 函 数 体 ” 等 节 详 细 地描 述 了 函 数 定 义 的 组 成 份 。
函 数 属 性
Microsoft 特 殊 处 →
任 选 的 属 性 序 列 非 终 结 符 允 许 你 在 每 一 个 函 数 基 础 上 选 择 一 个 调 用 约
定 。 你 也 可 以 指 定 函 数 为 __ fastcall 或
Microsoft 特 殊 处 结 束
指 定 调 用 约 定
Microsoft 特 殊 处 →
_ _ inline。
有 关 调 用 约 定 的 信 息 ,参 见 联 机 “ M icrosoft Visual C++ 6.0 程 序 员 指 南 ” 中 的 “ 调 用 约 定 主 题 ”。
Microsoft 特 殊 处 结 束
联 编 函 数
Microsoft 特 殊 处 →
__ inline 关 键 字 告 诉 编 译 器 在 一 个 函 数 调 用 的 每 个 实 例 中 用 该 函 数 的 定义 替 换 该 代 码 。 但 替 换 仅 出 现 在 编 译 器 的 决 定 中 。 例 如 , 如 果 一 个 函 数的 地 址 被 占 用 或 它 太 大 ,则 编 译 器 不 联 编 该 函 数 。
对 一 个 认 为 是 联 编 的 候 选 者 的 函 数 ,它 必 须 使 用 新 式 函 数 定 义 。使 用 这 个 格 式 指 出 一 个 联 编 函 数 :
__ inline 类型 opt 函 数 定 义 ;
使 用 联 编 函 数 产 生 更 快 的 代 码 , 有 时 产 生 比 相 同 函 数 调 用 产 生 更 小 的 代码 ,其 原 因 如 下 :
-
它 节 省 需 要 执 行 函 数 调 用 的 时 间 。
-
小 的 联 编 函 数 , 可 能 三 行 或 更 少 , 因 为 编 译 器 不 产 生 处 理 参 量 和 返 回值 的 代 码 而 生 成 比 相 同 的 函 数 调 用 更 少 的 代 码 。
-
生 成 的 联 编 函 数 是 属 于 不 能 正 常 使 用 的 优 化 代 码 , 因 为 编 译 器 不 执行 内 部 过 程 的 优 化 。
使 用 __ inline 的 函 数 不 要 与 联 编 汇 编 器 混 淆 , 有 关 更 多 信 息 参 见 “ 联 编 汇编 器 ”。
Microsoft 特 殊 处 结 束
联 编 汇 编 器
Microsoft 特 殊 处 →
联 编 汇 编 器 让 你 在 你 的 C 源 程 序 中 直 接 嵌 入 汇 编 语 言 指 令 而 不 要 额 外的 汇 编 和 链 接 步 骤 。
联 编 汇 编 器 构 建 在 编 译 器 中 , 你 不 需 要 单 独 的 汇 编 器 例 如 M icrosoft 宏 汇编 器 ( M A S M )。
因 为 该 联 编 汇 编 器 不 需 要 单 独 的 汇 编 和 链 接 步 骤 , 它 比 一 个 单 独 的 汇 编器 更 方 便 。 联 编 汇 编 代 码 可 以 使 用 任 何 C 变 量 或 函 数 名 称 ,因 此 它 容 易与 你 的 程 序 的 C 代 码 集 成 在 一 起 。 又 因 为 汇 编 代 码 可 以 与 C 语 句 混 合 , 因 此 它 可 以 完 成 单 独 用 C 很 麻 烦 的 或 不 可 能 的 功 能 。
__ asm 关 键 字 调 用 联 编 汇 编 器 , 它 可 以 出 现 在 任 何 合 法 的 C 语 句 中 , 但 不能 出 现 自 身 的 语 句 中 。 之 后 必 须 跟 一 个 汇 编 指 令 、 一 个 用 花 括 号 括 起 的指 令 组 或 者 至 少 一 个 空 花 括 号 对 。
术 语 “ __ asm 块 ” 在 这 里 指 的 是 任 何 指 令 或 指 令 组 ,不 论 是 否 出 现 在 花 括号 中 。
下 面 的 代 码 是 一 个 花 括 号 括 起 的 简 单 __ asm 块 ( 这 个 代 码 是 一 个 空 制 函数 ):
__ asm
{
push ebp mov ebp,esp
sub esp, __ LOCAL_SIZE
}
另一种方式 , 你可以在每个汇编指令前面放置一个 __ asm:
__ asm push ebp
__ asm mov ebp,esp
__ asm sub esp, __ LOCAL_SIZE
由 于 __ asm 关 键 字 是 一 个 语 句 分 隔 符 , 你 也 可 以 把 汇 编 指 令 放 在 同 一 行 中 :
__ asm push ebp __ asm mov ebp,esp __ asm sub esp, __ LOCAL_SIZE Microsoft 特 殊 处 结 束
DLL 输 入 和 输 出 函 数
Microsoft 特 殊 处 →
dllimport 和 dllexport 存 储 类 修 饰 符 是 C 语 言 的 M icrosoft 特 殊 处 扩 充 。这 些 修 饰 显 式 定 义 了 DLL 的 客 户 界 面 ( 可 执 行 的 文 件 或 另 外 的 DLL )。说 明 为 dllexport 的 函 数 消 除 了 一 个 模 块 定 义 (.DLL )文 件 的 需 要 。 你 可 以为 数 据 和 对 象 使 用 dllimport 和 dllexport 修 饰 符 。
dllimport 和 dllexport 存 储 类 修 饰 符 必 须 与 扩 充 的 属 性 语 法 关 键 字
__ declspec 一 起 使 用 ,下 面 是 这 样 的 例 子 : #define DllImport __ declspec(dllimport) #define DllExport __ declspec(dllexport)
DllExport void func();
Dllexport int i = 10; DllExport int j; DllExport int n;
有关扩充的存储类修饰符的语法的指定信息 ,参 见 第 3 章 “说明和类型”中的 “扩
充的存储类型属性 ”。
Microsoft 特 殊 处 结 束
定 义 和 说 明
Microsoft 特 殊 处 →
DLL 界 面 指 的 是 系 统 中 某 个 程 序 中 输 出 的 所 有 已 知 项 ( 函 数 和 数 据 ); 也就 是 所 有 说 明 为 dllimport 或 dllexport 的 所 有 项 。 包 括 在 DLL 界 面 中 的所 有 说 明 必 须 指 定 为 dllimport 或 dllexport 属 性 。 但 该 定 义 只 能 指 定dllexport 属 性 。 例 如 , 如 下 函 数 定 义 生 成 一 个 编 译 器 错 误 :
#define DLLImport __ declspec(dllimport) #define DLLExport __ declspec(dllexport)
DLLImport int func()/* 错误 :在定义中禁止 dllimport*/
{
return 1;
}
下 面 代 码 也 产 生 一 个 错 误 :
#define DllImport __ declspec(dllimport)
#define DllExport __ declspec(dllexport)
DllImport int i=10; /* 错误 : 这是一个定义 */
但如下是正确的语法 :
#define DllImport __ declspec(dllimport) #define DllExport __ declspec(dllexport)
DllExport int i=10; /* 正确 : 这是一个输出定义 */
dllexport 的使用隐含一个定义 , 而 dllimport 隐含一个说明。你必须对 dllexport 使用
extern 关键字强制为一个说明 ;否则 , 隐含是一个定义。
#define DllImport __ declspec(dllimport) #define DllExport __ declspec(dllexport)
extern DllImport int k; /* 这是正确的并隐含一个说明 */ Dllimport int j;
M icrosoft 特殊处结束
用 dllexport 和 dllimport 定 义 联 编 函 数
Microsoft 特 殊 处 →
你 可 以 用 dllexport 属 性 定 义 一 个 联 编 函 数 , 在 这 种 情 况 下 ,该 函 数 总 是 被实 例 化 和 被 输 出 , 无 论 程 序 中 的 任 何 模 块 引 用 该 函 数 。 该 函 数 假 定 是 被另 一 程 序 输 入 。
你 也 可 以 用 dllimport 属 性 说 明 一 个 函 数 为 联 编 函 数 , 在 这 种 情 况 下 , 该 函数 可 以 被 伸 展 ( 从 属 于 /Ob( 联 编 ) 编 译 器 选 项 规 格 ) 但 不 能 被 实 例 化 。 在 特殊 情 况 中 , 如 果 一 个 联 编 输 入 的 函 数 的 地 址 被 占 用 , 该 函 数 的 地 址 保 留 在返 回 的 DLL 中 。 这 个 行 为 和 占 用 一 个 非 联 编 输 入 的 函 数 的 地 址 相 同 。在 联 编 函 数 中 的 静 态 局 部 数 据 和 字 符 串 在 DLL 和 象 在 单 个 程 序 中 似 的客 户 ( 也 就 是 , 一 个 没 有 DLL 界 面 的 可 执 行 文 件 ) 之 间 维 护 相 同 的 标 识符 。
在 进 行 提 供 输 入 的 联 编 函 数 的 练 习 时 要 小 心 ,例 如 ,如 果 你 修 改 DLL ,不 要假 设 该 客 户 使 用 该 DLL 的 改 变 的 版 本 。 为 了 保 证 你 加 载 适 当 的 DLL 版本 ,重 新 建 立 该 DLL 的 客 户 。
Microsoft 特 殊 处 结 束
dllimport/dllexport 的 规 则 和 限 制
Microsoft 特 殊 处 →
-
如 果 你 说 明 一 个 函 数 没 有 dllimport 或 dllexport 属 性 , 该 函 数 不认 为 是 DLL 界 面 的 部 分 。 因 此 , 该 函 数 的 定 义 必 须 出 现 在 该 模 块 中或 相 同 程 序 的 另 一 个 模 块 中 。 为 了 使 该 函 数 成 为 DLL 界 面 部 分 , 必须 在 其 它 模 块 中 以 dllexport 说 明 该 函 数 的 定 义 ; 否则 , 在 建 立 客 户时 产 生 一 个 链 接 器 错 误 。
-
如 果 你 的 程 序 的 单 个 模 块 包 含 相 同 函 数 的 dllimport 和 dllexport 说 明 , 那 么 dllexport 属 性 的 优 先 级 比 dllimport 属 性 的 优 先 级 高 。但 编 译 器 产 生 一 个 警 告 。 例 如 :
#define DLLimport __ declspec(dllimport) #define DLLexport __ declspec(dllexport)
DllImport void func1(void);
DllExport void func1(void);/* 警告 :dllexport 更优先 */
- 你 不 能 用 一 个 以 dllimport 属 性 说 明 的 数 据 对 象 的 地 址 初 始 化 一 个静 态 数 据 指 针 。 例 如 , 如 下 代 码 产 生 一 个 错 误 :
#define DllImport __ declspec(dllimport) #define DllExport __ declspec(dllexport)
DllImport int i ;
.
.
.
int *pi=&i; /* 错 误 */
void func2()
{
static int *pi=&i; /* 错 误 */
} )
- 用 一 个 dllimport 说 明 的 函 数 的 地 址 初 始 化 一 个 静 态 函 数 指 针 , 设置 该 指 针 为 该 DLL 输 入 形 实 替 换 程 序 ( 一 个 转 换 控 制 到 该 函 数 的 代码 块 ) 而 不 是 该 函 数 的 地 址 。 如 下 赋 值 不 产 生 错 误 消 息 :
#define D ll Import __ declspec(dllimport) #define DllExport __ declspec(dllexport)
DllImport void func1(void)
.
.
.
static void (*pf)(void)=&func1;/* 没 有 错 误 */
void func2()
{
static void (*pf)(void)=&func1;/* 没 有 错 误 */
}
- 因 为 在 一 个 对 象 的 说 明 中 包 括 dllexport 属 性 的 程 序 必 须 提 供 这 个对 象 的 定 义 , 你 可 以 用 一 个 dllexport 函 数 的 地 址 初 始 化 一 个 全 局或 局 部 静 态 函 数 指 针 。 类 似 地 , 你 可 以 用 一 个 dllexport 数 据 对 象的 地 址 初 始 化 一 个 全 局 或 局 部 静 态 数 据 指 针 。 例 如 :
#define DllImport __ declspec(dllimport) #define DllExport __ declspec(dllexport)
DllImport void func1(void); DllImport int i;
DllExport void func1(void); DllExport int i;
.
.
.
int *pi=&i; /* 正确 */
static void(*pf)(void) = &func1; /* 正确 */
void func2()
{
static int *pi=i; /* 正确 */
static void (*pf)(void) = &func1; /* 正确 */
}
M icrosoft 特殊处结束
naked 函 数
Microsoft 特 殊 处 →
naked 存 储 类 属 性 是 C 语 言 的 一 个 M icrosoft 特 殊 处 扩 充 。 对 于 用 naked 存 储 类 属 性 说 明 的 函 数 , 编 译 器 生 成 没 有 序 言 和 结 尾 部 分 的 代 码 。 你 可以 利 用 这 个 特 征 , 在 使 用 联 编 写 虚 拟 设 备 驱 动 程 序 中 特 别 有 用 。
因 为 naked 属 性 仅 与 一 个 函 数 的 定 义 有 关 ,它 不 是 一 个 类 型 修 饰 符 ,naked
函 数 使 用 第 3 章 “ 说 明 和 类 型 ” 中 的 “ 扩 充 的 存 储 类 属 性 ” 中 描 述 的 扩充 的 属 性 语 法 。
下 面 的 例 子 用 naked 属 性 定 义 了 一 个 函 数 :
__ declspec(naked)int func(formal_parameters)
{
/* 函数体 */
}
或者 ,另一种方式是 :
#define naked __ declspec (naked)
naked int func(formal_parameters)
{
/* 函数体 */
}
naked 属 性 只 影 响 编 译 器 生 成 该 函 数 的 序 言 和 结 尾 部 分 序 列 的 代 码 ,它 不影 响 调 用 这 样 函 数 生 成 的 代 码 。 因 此 ,naked 属 性 不 认 为 是 该 函 数 的 类 型部 分 , 函 数 指 针 不 能 有 naked 属 性 。 而 且 naked 属 性 不 能 应 用 于 一 个 数 据定 义 。 例 如 ,如 下 代 码 产 生 错 误 :
__ declspec(naked) int i; /* 错 误 -naked 属 性 不 允 许 用 在 数 据 说 明 中 */ naked 属 性 只 能 与 函 数 的 定 义 相 关 , 而 不 能 在 函 数 的 原 型 中 指 出 , 下 面 的说 明 产 生 一 个 编 译 器 错 误 :
__ declspec(naked) int func(); /* 错 误 -naked 属 性 不 允 许 在 函 数 说 明 中 */
Microsoft 特 殊 处 结 束
使 用 naked 函 数 的 规 则 和 限 制
Microsoft 特 殊 处 →
-
在 一 个 naked 函 数 中 不 允 许 使 用 return 语 句 。 但 可 以 把 该 返 回 值移 到 RET 指 令 之 前 的 EAX 寄 存 器 。
-
在 一 个 naked 函 数 中 不 允 许 使 用 结 构 的 异 常 处 理 指 令 , 因 为 该 指 令必 须 在 栈 框 架 中 执 行 取 消 内 务 操 作 。
-
在 一 个 naked 函 数 中 不 允 许 使 用 setjmp 运 行 函 数 , 因 为 它 必 须 在 栈框 架 中 执 行 取 消 内 务 操 作 。 但 longjmp 运 行 函 数 是 允 许 的 。
-
在 一 个 naked 函 数 中 不 允 许 使 用 _alloc 函 数 。
-
为 了 确 保 在 序 言 之 前 不 出 现 局 部 变 量 的 初 始 化 代 码 , 在 函 数 范 围 不允 许 初 始 化 的 局 部 变 量 。
-
不 推 荐 使 用 框 架 指 针 优 化 (/Oy 编 译 器 选 项 ), 但 它 为 了 naked 函 数 而自 动 取 消 。
Microsoft 特 殊 处 结 束
编 写 序 言 /结 尾 部 分 代 码 的 考 虑
Microsoft 特 殊 处 →
在 你 编 写 自 已 的 序 言 和 结 尾 部 分 代 码 序 列 之 前 , 重 要 的 是 了 解 栈 框 架 的布 局 , 它 对 于 了 解 如 何 使 用 __LOCAL_SIZE 预 定 义 的 常 量 也 是 重 要 的 。
栈 框 架 布 局
这 个 例 子 说 明 了 在 一 个 32 位 函 数 中 可 以 出 现 的 标 准 序 言 代 码 :
push |
ebp |
;存储 ebp |
---|---|---|
mov |
ebp,esp |
;设 置 栈 框 架 指 针 |
sub |
esp,localbytes |
;为局部变量分配空间 |
push |
<registers> |
;存储 registers |
localbytes 变 量 表 示 在 栈 上 局 部 变 量 需 要 的 字 节 数 ,registers 变 量 是 表 示在 栈 上 保 存 寄 存 器 表 的 位 置 占 用 者 。 在 下 推 寄 存 器 后 , 你 可 以 把 任 何 其它 适 当 的 数 据 放 在 栈 中 。 如 下 是 对 应 的 结 尾 部 分 代 码 :
pop |
<registers> |
; 恢复 registers |
---|---|---|
mov |
esp ebp |
;恢复栈指针 |
pop |
ebp |
;恢复 ebp |
ret |
;从函数返回 |
栈 总 是 向 下 推 ( 从 高 到 低 存 储 器 地 址 )。 基 指 针 (ebp) 指 向 ebp 的 推 入 的 值 , 局 部 变 量 区 域 起 始 于 ebp-2 。 为 了 访 问 该 局 部 变 量 , 通 过 ebp 减 适 当 的 值计 算 从 ebp 的 偏 移 量 。
__ LOCAL_SIZE 常 量
编 译 器 为 联 编 汇 编 器 块 中 使 用 函 数 序 言 代 码 而 提 供 了 一 个 常 量
__ LOCAL_SIZE 。 这 个 常 量 用 在 定 制 序 言 代 码 中 用 于 在 栈 上 为 局 部 变 量分 配 空 间 。
编 译 器 确 定 __ LOCAL_SIZE 的值 , 该 值 是 所 有 用 户 定 义 的 局 部 变 量 和 编 译
器 生 成 的 临 时 变 量 的 总 的 字 节 个 数 。 __ LOCA L __SIZE 仅 用 作 一 个 立 即 操作 数 ; 它 不 能 用 在 一 个 表 达 式 中 。
你 不 能 改 变 或 重 新 定 义 该 常 量 的 值 。 例 如 :
mov eax, __ LOCAL_SIZE ; 立即操作数 - 正确
mov eax, [ebp-__ LOCAL_SIZE] ; 错误
如 下 一 个 naked 函 数 的 例 子 包 含 定 制 序 言 和 结 尾 部 分 序 列 :
__ declspec( naked ) func()
{
int i; int j;
__ asm /* 序言 */
{
push ebp mov ebp,esp
sub esp ,__ LOCAL_SIZE
}
/* 函数体 */
__ asm /* 结尾部分 */
{
mov esp,ebp pop ebp
ret
}
}
存 储 类
Microsoft 特 殊 处 结 束
在 函 数 定 义 中 的 存 储 类 给 出 该 函 数 为 extern 或 static 存 储 类 。
语法 :
函数定义 :
说明指示符 opt 属性序列 opt 说 明 符 说明表 opt 复合语句
/* 属性序列是 M icrosoft 特殊处 */
说明指示符 :
存储类指示符 说明指示符 opt 类型指示符 说明指示符 opt 类型修饰符 说明指示符 opt
存储类指示符 : /* 对于函数定义 */ extern
static
如 果 一 个 不 包 括 存 储 类 指 示 符 的 函 数 定 义 ,该 存 储 类 缺 省 为 extern 。 你 可以 显 式 说 明 一 个 函 数 为 extern, 但 它 可 以 不 需 要 。
如 果 一 个 函 数 说 明 包 含 存 储 类 指 示 符 extern ,该 标 识 符 和 任 何 文 件 范 围 的标 识 符 的 可 见 说 明 具 有 相 同 的 连 接 。 如 果 没 有 文 件 范 围 的 可 见 说 明 , 该标 识 符 具 有 外 部 的 连 接 。 如 果 一 个 标 识 符 有 文 件 范 围 且 没 有 存 储 类 指 示
符 , 那 么 该 标 识 符 具 有 外 部 的 连 接 。 外 部 的 连 接 意 味 着 该 标 识 符 的 每 个实 例 指 示 相 同 的 对 象 或 函 数 。 有 关 连 接 和 文 件 范 围 的 更 多 信 息 参 见 第 2 章 “ 程 序 结 构 ” 中 的 “ 生 存 期 、 范 围 、 可 见 性 和 连 接 ”。
用 一 非 extern 的 存 储 类 指 示 符 说 明 一 个 块 范 围 的 函 数 会 产 生 错 误 。
具 有 static 存 储 类 的 一 个 函 数 仅 在 定 义 它 的 源 文 件 中 是 可 见 的 。 所 有 其它 函 数 , 不 论 它 们 是 显 式 还 是 隐 含 地 给 出 extern 存 储 类 ,它 们 在 程 序 中 的所 有 源 文 件 中 都 是 可 见 的 。 如 果 期 待 是 static 存 储 类 ,必 须 在 该 函 数 说 明 ( 如 果 有 ) 的 第 一 次 出 现 或 者 该 函 数 的 定 义 上 说 明 它 为 该 存 储 类 。Microsoft 特 殊 处 →
当 允 许 M icrosoft 扩 充 时 ,最 初 说 明 没 有 一 个 存 储 类 ( 或 有 extern 存 储 类 ) 的 函 数 , 如 果 该 函 数 的 定 义 在 同 一 源 文 件 中 , 且 该 定 义 显 式 指 出 static 存储 类 , 则 该 函 数 给 出 为 static 存 储 类 。
当 用 /Ze 编 译 器 选 项 编 译 时 ,在 一 个 块 中 用 extern 关 键 字 说 明 的 函 数 具 有全 局 可 见 性 。
当 用 /Za 编 译 时 不 是 这 样 的 。 如 果 考 虑 源 代 码 的 移 植 性 , 这 个 特 征 是 不 可靠 的 。
Microsoft 特 殊 处 结 束
返 回 类 型
一 个 函 数 的 返 回 值 建 立 该 函 数 返 回 值 的 尺 寸 和 类 型 , 对 应 于 下 面 语 法 中的 类 型 指 示 符 :
语法
函数定义 :
说明指示符 opt 属性序列 opt 说 明 符 说明表 opt 复合语句
/* 属性序列是 M icrosoft 特殊处 */
说明指示符 :
存储类指示符 说明指示符 opt
类型指示符 说明指示符 opt
类型修饰符 说明指示符 opt
类型指示符 : void char short int
long float double signed unsigned
结构或联合指示符枚 举 指 示 符 typedef 名称
类 型 指 示 符 可 以 指 出 任 何 基 本 的 、 结 构 或 联 合 类 型 。 如 果 你 不 包 括 类 型
指 示 符 , 返 回 的 类 型 假 设 是 int。
在 函 数 定 义 中 给 出 的 返 回 值 必 须 与 在 程 序 中 其 它 地 方 该 函 数 说 明 的 返 回值 相 匹 配 。 当 执 行 包 含 一 个 表 达 式 的 return 语 句 时 一 个 函 数 返 回 一 个值 。 对 该 表 达 式 求 值 时 , 如 果 需 要 , 要 转 换 该 返 回 值 的 类 型 ,并 返 回 到 该 函数 被 调 用 的 地 方 。 如 果 一 个 函 数 被 说 明 为 返 回 类 型 是 void, 则 一 个 包 含表 达 式 的 返 回 语 句 会 产 生 一 个 警 告 ,并 不 对 其 中 的 表 达 式 进 行 求 值 。
如 下 例 子 说 明 了 函 数 的 返 回 值 :
typedef struct
{
char name[20]; int id;
long class;
} STUDENT;
/* 返回的类型是 STUDENT */
STUDENT sortstu(STUDENT a,STUDENT b)
{
return((a.id < b.id) ? a : b);
}
这 个 例 子 用 一 个 typedef 说 明 定 义 了 STUDENT 类 型 ,并 定 义 函 数 sortstu 具 有 STUDENT 返 回 类 型 。 该 函 数 选 择 并 返 回 它 的 两 个 结 构 参 量 之 一 。在 该 函 数 的 后 续 调 用 中 ,编 译 器 进 行 检 测 以 确 保 参 量 类 型 为 STUDEN T 。注意 : 通 过 传 送 该 结 构 的 指 针 而 不 是 整 个 结 构 可 以 提 高 效 率 。
char *smallstr(char s1[],char s2[])
{
int i;
i=0;
while (s1[i]!= ′ \0 ′ & & s2[i]!= ′ \0 ′ ) i++;
if (s1[i]== ′ \0 ′ )
return(s1); else
return(s2);
}
这 个 例 子 定 义 了 一 个 这 样 的 函 数 , 该 函 数 返 回 一 个 字 符 数 组 的 指 针 。 该函 数 有 两 个 字 符 数 组 的 ( 字 符 串 ) 参 量 并 返 回 两 个 字 符 串 中 较 短 的 指 针 , 一个 数 组 的 指 针 指 向 第 一 个 数 组 元 素 并 具 有 它 的 类 型 ; 因 此 , 该 函 数 的 返 回类 型 是 char 类 型 的 指 针 。
对 于 返 回 int 类 型 的 函 数 ,你 不 需 要 在 调 用 它 们 之 前 说 明 它 的 int 返 回 类型 ,虽 然 建 议 使 用 原 型 以 便 对 参 量 和 返 回 值 进 行 正 确 的 类 型 检 测 。
参 数
参 量 是 通 过 一 个 函 数 调 用 传 给 该 函 数 的 值 的 名 称 , 参 数 是 该 函 数 期 待 接受 的 值 。 在 一 个 函 数 原 型 中 , 紧 跟 函 数 名 称 后 面 的 圆 括 号 包 含 该 函 数 的
参 数 及 其 类 型 的 完 整 表 。
参 数 说 明 指 出 存 储 在 参 数 中 的 值 的 类 型 、 尺 寸 和 标 识 符 。
语法
函数定义 :
说明指示符 opt 属性序列 opt 说 明 符 说明表 opt 复合语句
/* 属性序列是 M ic rosoft 特殊处 */
说明符 :
指针 opt 直接说明符
直接说明符 : /* 一个函数说明符 */
直接说明符 ( 参数类型表 )/* 新式说明符 */
参数类型表 : /* 一个参数表 */
参数表 参数表 ,...
参数表 :
参数说明
参数表 ,参数说明参数说明 :
说明指示符 ,说 明 符
说明指示符 ,抽象说明符 opt
参 数 类 型 表 是 一 个 由 逗 号 分 隔 的 参 数 说 明 序 列 。 在 参 数 表 中 每 个 参 数 的
格 式 如 下 :
[register] 类 型 指 示 符 [ 说 明 符 ]
用 auto 属 性 说 明 函 数 参 数 会 产 生 错 误 , 该 参 数 的 标 识 符 用 在 函 数 体 中 指的 是 送 给 该 函 数 的 值 。 你 不 能 在 原 型 中 命 名 参 数 , 除 非 这 些 名 称 超 出 该说 明 结 尾 的 范 围 。 因 此 参 数 名 称 可 以 与 函 数 定 义 中 相 同 方 式 或 不 同 方 式赋 值 。 这 些 标 识 符 在 函 数 体 的 最 外 层 的 块 中 不 能 重 新 定 义 , 但 它 们 可 以在 里 层 、 嵌 套 的 块 中 好 像 参 数 表 是 一 个 括 起 来 的 块 重 新 定 义 。
在 参 数 类 型 表 中 的 每 个 标 识 符 之 前 必 须 有 适 当 的 类 型 指 示 符 , 正 如 下 面的 例 子 指 示 的 :
void new (double x, double y, double z)
{
/* 这里是函数体 */
}
如 果 在 参 数 表 中 至 少 出 现 一 个 参 数 , 该 表 可 以 以 一 个 逗 号 跟 三 个 句 点 (,...) 结 尾 。 这 个 构 造 称 为 “ 省 略 用 法 ”, 指 出 该 函 数 可 变 的 参 量 个 数 ( 有 关 更多 信 息 , 参 见 本 章 后 面 的 “ 用 可 变 个 数 参 量 调 用 ” ) 。 但 调 用 该 函 数 的 参量 个 数 必 须 至 少 有 逗 号 之 前 的 参 数 个 数 多 。
如 果 没 有 参 量 传 送 给 该 函 数 , 该 参 数 表 由 关 键 字 void 代 替 ,这 个 void 的 使用 不 同 于 作 为 一 个 类 型 指 示 符 的 使 用 。
参 数 的 次 序 和 类 型 包 括 任 何 省 略 用 法 , 在 所 有 函 数 说 明 ( 如 果 有 ) 和 函 数 定义 中 必 须 都 是 相 同 的 。 在 常 用 算 术 转 换 之 后 参 量 的 类 型 必 须 与 对 应 参 数的 类 型 进 行 兼 容 赋 值 ( 对 于 算 术 转 换 的 信 息 参 见 第 4 章 “ 表 达 式 和 赋 值 ” 中 的 “ 常 用 的 算 术 转 换 ” ), 省 略 号 后 的 参 量 不 进 行 检 测 。 一 个 参 数 可 以有 任 何 基 本 的 、 结 构 、 联 合 、 指 针 或 数 组 类 型 。
函 数 体
如 果 必 要 , 编 译 器 在 每 个 参 数 和 每 个 参 量 上 执 行 独 立 的 常 用 算 术 转 换 。在 转 换 之 后 ,没 有 短 于 int 的 参 数 ,没 有 参 数 具 有 float 类型 , 除 非 该 参 数 类型 在 原 型 中 显 式 指 定 为 float 。 例 如 ,这 意 味 着 说 明 一 个 参 数 为 char 与 说明 它 为 int 具 有 相 同 的 作 用 。
一 个 “ 函 数 体 ” 是 包 含 指 定 该 函 数 执 行 的 语 句 的 复 合 语 句 。
语法
函数定义 :
说明指示符 opt 属性序列 opt 说 明 符 说明表 opt 复合语句
/* 属性序列是 M icrosoft 特殊处 */
复合语句 : /* 函 数 体 */
{ 说明表 opt 语 句 表 opt }
在 一 个 函 数 体 中 说 明 的 变 量 、“ 局 部 变 量 ” 除 非 指 定 其 它 的 存 储 类 型 , 否
则 具 有 auto 存 储 类 。 当 一 个 函 数 被 调 用 时 , 为 局 部 变 量 建 立 存 储 并 执 行局 部 初 始 化 。 执 行 控 制 传 给 该 复 合 语 句 中 的 第 一 个 语 句 并 继 续 执 行 直 到遇 到 一 个 return 语 句 或 遇 到 该 函 数 体 结 束 。 然 后 控 制 返 回 到 函 数 被 调 用的 地 方 。
如 果 该 函 数 有 一 个 返 回 值 , 必 须 执 行 包 含 一 个 表 达 式 的 return 语 句 。 如果 没 有 return 语 句 执 行 或 者 return 语 句 不 包 含 表 达 式 ,该 函 数 的 返 回 值 是不 确 定 的 。
函 数 原 型
- 个 函 数 说 明 位 于 函 数 定 义 之 前 , 指 出 一 个 函 数 的 名 称 、 返 回 类 型 、 存储 类 型 和 其 它 属 性 。 为 了 作 为 一 个 原 型 使 用 , 该 函 数 说 明 也 必 须 建 立 该函 数 参 量 的 类 型 和 标 识 符 。
语法说明 :
说明指示符 属性序列 opt 初始说明符表 opt
/* 属性序列 opt 是 M icrosoft 特 殊 处 */
说明指示符 :
存储类指示符 说明指示符 opt
类型指示符 说明指示符 opt
类型修饰符 说明指示符 opt
初始说明符表 :
初始说明符
初始说明符表 , 初始说明符初始说明符 :
说明符
说明符 = 初始化器说明符 :
指针 opt 直接说明符
直接说明符 : /* 一个函数说明符 */
直接说明符 ( 参数类型表 ) /* 新式说明符 */
直接说明符 ( 标识符表 opt ) /* 已废除的说明符 */
该 原 型 和 函 数 定 义 具 有 相 同 的 格 式 , 除 了 一 个 分 号 直 接 跟 在 圆 括 号 之 后终 止 原 型 外 , 因 此 原 型 没 有 语 句 体 。 在 每 种 情 况 下 , 返 回 值 必 须 与 函 数 定义 中 指 定 的 返 回 值 一 致 。
函 数 原 型 具 有 如 下 重 要 用 途 :
-
它 们 建 立 函 数 返 回 非 int 类 型 的 返 回 类 型 , 虽 然 返 回 int 值 的 函 数不 需 要 原 型 , 但 建 议 有 原 型 。
-
没 有 完 成 的 原 型 , 要 进 行 标 准 转 换 , 但 不 要 试 图 用 参 数 个 数 检 测 参 量的 类 型 和 个 数 。
-
原 型 在 函 数 定 义 之 前 用 于 初 始 化 该 函 数 的 指 针 。
-
参 数 表 用 于 对 函 数 定 义 中 的 参 数 与 函 数 调 用 中 对 应 的 参 量 进 行 检测 。
每 个 参 数 转 换 的 类 型 确 定 了 栈 中 放 置 的 函 数 调 用 参 量 的 解 释 。 参 量 和 参数 之 间 的 一 个 类 型 不 匹 配 导 致 栈 中 的 参 量 被 误 解 释 。 例 如 , 在 一 个 16 位计 算 机 中 ,如 果 一 个 16 位 指 针 作 为 一 个 参 量 传 送 , 那 么 说 明 作 为 一 个 long 参 数 , 栈 中 的 开 头 32 位 解 释 为 一 个 long 参 数 。
这 个 错 误 不 仅 对 该 long 参 数 产 生 问 题 , 而 且 对 于 随 后 的 任 何 参 数 也 产 生问 题 。 你 可 以 通 过 所 有 函 数 说 明 完 整 的 函 数 原 型 来 检 测 这 种 错 误 。
- 个 原 型 建 立 一 个 函 数 的 属 性 , 以 便 在 其 定 义 ( 或 出 现 在 其 它 源 文 件 中 ) 之前 的 函 数 调 用 检 测 参 数 类 型 和 返 回 类 型 的 不 匹 配 。 例 如 , 如 果 你 在 一 个原 型 中 指 出 static 存 储 表 指 示 符 ,你 必 须 在 函 数 定 义 中 指 定 static 存 储 类 。
完 整 参 数 说 明 (int a) 可 以 在 同 一 说 明 中 与 抽 象 说 明 符 (int) 混 合 使 用 。 例如 ,如 下 说 明 是 合 法 的 :
int add (int a,int);
该 原 型 可 以 包 括 两 种 形 式 , 一 种 是 类 型 , 一 个 是 标 识 符 , 每 个 表 达 式 作 为 一个 参 量 传 送 。
但 这 样 的 标 识 符 的 范 围 只 有 到 该 说 明 结 束 为 止 。 原 型 也 可 以 反 映 参 量 个数 是 可 变 的 事 实 , 或 者 没 有 传 送 的 参 量 。 没 有 这 样 的 一 个 表 , 不 会 反 映 出不 匹 配 , 因 此 编 译 器 不 能 生 成 有 关 它 们 的 诊 断 消 息 , 有 关 类 型 检 测 的 更 多信 息 , 参 见 本 章 后 面 的 “ 参 量 ”。
现 在 M icrosoft C 编 译 器 的 原 型 范 围 在 使 用 /Za 编 译 器 选 项 编 译 时 是 与ANSI 一 致 的 。 这 意 味 着 如 果 你 在 一 个 原 型 中 说 明 一 个 struct 或 union 标志 ,该 标 志 进 入 这 个 范 围 而 不 是 一 个 全 局 范 围 。 例 如 ,当 用 /Za 与 ANSI 一致 性 的 方 式 编 译 时 , 你 不 调 用 这 个 函 数 不 会 得 到 一 个 类 型 不 匹 配 的 错 误 : void func1(struct s*);
为 了 修 正 你 的 代 码 , 在 该 函 数 原 型 之 前 以 全 局 范 围 定 义 或 说 明 为 struct 或
union:
struct s;
void func1(struct s*);
在 /Ze 下 , 该 标 志 仍 进 入 全 局 范 围 中 。
函 数 调 用
一 个 函 数 调 用 是 一 个 传 送 控 制 和 参 量 ( 如 果 有 ) 给 一 个 函 数 的 表 达 式 , 它 有格 式 :
表 达 式 ( 表 达 式 表 opt)
这 里 的 表 达 式 是 一 个 函 数 名 称 或 一 个 函 数 地 址 的 求 值 , 表 达 式 表 是 一 个表 达 式 ( 用 逗 号 分 隔 ) 的 表 。 这 些 表 达 式 的 最 后 值 是 传 送 给 该 函 数 的 参量 。 如 果 该 函 数 不 返 回 一 个 值 ,那 么 你 说 明 它 为 一 个 返 回 void 的 函 数 。如 果 一 个 说 明 在 函 数 调 用 之 前 存 在 , 但 没 有 给 出 有 关 参 数 的 信 息 , 任 何 未说 明 的 参 量 简 单 地 经 历 常 用 的 算 术 转 换 。
注 意 : 函 数 参 量 表 中 的 表 达 式 可 以 以 任 何 次 序 求 值 。 因 此 其 值 被 其 它 参量 的 副 作 用 所 改 变 的 参 量 具 有 不 确 定 的 值 。 函 数 调 用 运 算 符 所 定 义 的 顺序 点 仅 保 证 参 量 中 的 所 有 副 作 用 在 控 制 传 送 给 被 调 用 函 数 之 前 被 求 值( 注 意 ,参 量 推 入 栈 的 次 序 是 另 一 个 事 情 ) 。有 关 更 多 信 息 参 见 第 4 章“ 表达 式 和 赋 值 ” 中 的 “ 顺 序 点 ”。
在 任 何 函 数 调 用 中 的 唯 一 要 求 是 圆 括 号 之 前 的 表 达 式 必 须 求 值 为 一 个 函数 地 址 。 这 意 味 着 一 个 函 数 可 以 通 过 任 何 函 数 指 针 表 达 式 调 用 。
例 子
这 个 例 子 说 明 函 数 调 用 ,它 从 一 个 switch 语 句 调 用 函 数 :
void main()
{
/* 函数原型 */
long lift(int),step(int),drop(int);
void work(int number,long (*function)(int i)); int select,count;
.
.
.
select =1; switch(select)
{
case 1:work(count,lift);
break;
case 2:work(count,step);
break;
case 3:work(count,drop);
/* 进入到下一个 case */ default:
break;
}
}
/* 函数定义 */
void work(int number,long (*function)(int i))
{
int i; long j;
for (i=j=0;i<number;i++) j += (*function)(i);
}
在 这 个 例 子 中 , 函 数 在 main 中 调 用 :
work (count, lift),
它 传 送 一 个 整 数 变 量 count 和 函 数 lift 的 地 址 给 函 数 work 。 注 意 该 函 数的 地 址 通 过 给 出 的 函 数 标 识 符 简 单 地 传 送 , 由 于 一 个 函 数 标 识 符 求 值 为一 个 指 针 表 达 式 。 为 了 以 这 种 方 式 使 用 一 个 函 数 标 识 符 , 函 数 必 须 在 该标 识 符 被 使 用 之 前 说 明 或 定 义 ; 否 则 , 不 认 识 该 标 识 符 。 在 这 种 情 况下 ,work 的 一 个 原 型 在 main 函 数 的 开 头 给 出 。
work 中 的 参 数 function 说 明 为 一 个 这 样 的 函 数 的 一 个 指 针 , 该 函 数 有 一个 int 参 量 和 返 回 一 个 long 值 。 括 起 参 数 名 称 的 圆 括 号 是 需 要 的 ;没 有它 们 , 该 说 明 指 出 一 个 返 回 long 值 指 针 的 函 数 。
函 数 work 从 for 循 环 中 通 过 作 用 如 下 函 数 调 用 方 式 调 用 选 择 的 函 数 : (*function)(i);
一 个 参 量 i 传 送 给 被 调 用 的 函 数 。
参 量
在 一 个 函 数 调 用 中 的 参 量 具 有 这 种 格 式 :
表 达 式 ( 表 达 式 表 opt) /* 函 数 调 用 */
在 一 个 函 数 调 用 中 , 表 达 式 表 是 一 个 表 达 式 的 表 ( 由 逗 号 分 隔 )。 这 些 表 达式 的 最 终 值 传 送 给 函 数 的 参 量 。 如 果 该 函 数 没 有 参 量 , 表 达 式 包 含 关 键字 void 。
一 个 参 量 可 以 是 任 何 具 有 基 本 的 、 结 构 、 联 合 或 指 针 类 型 的 值 。 所 有 参量 都 通 过 值 传 送 。 这 意 味 着 把 该 参 量 的 拷 贝 赋 给 对 应 的 参 数 。 该 函 数 不知 道 传 送 的 参 量 的 实 际 存 储 器 位 置 。 该 函 数 使 用 这 个 拷 贝 不 影 响 最 初 导出 的 变 量 。
虽 然 你 不 能 作 为 参 量 传 送 数 组 或 函 数 , 你 可 以 传 送 它 们 的 指 针 。 指 针 提供 了 一 个 函 数 通 过 引 用 访 问 一 个 值 的 方 式 。 由 于 一 个 变 量 的 指 针 保 存 变量 的 地 址 , 函 数 使 用 这 个 地 址 访 问 该 变 量 的 值 。 指 针 参 量 允 许 一 个 函 数访 问 数 组 和 函 数 , 尽 管 数 组 和 函 数 不 能 作 为 参 量 传 送 。
参 量 求 值 的 次 序 在 不 同 编 译 器 下 和 不 同 的 优 化 层 中 可 能 发 生 变 化 。 但 在进 入 函 数 之 前 参 量 和 任 何 副 作 用 都 必 须 完 整 地 求 值 。 有 关 副 作 用 的 信 息参 见 第 4 章 “ 表 达 式 和 赋 值 ” 中 的 “ 副 作 用 ”。
在 一 个 函 数 调 用 中 的 表 达 式 被 求 值 并 在 函 数 调 用 中 每 个 参 量 上 执 行 常 用的 算 术 转 换 。 如 果 一 个 原 型 是 可 用 的 , 结 果 参 量 类 型 与 原 型 对 应 的 参 数进 行 比 较 。 如 果 它 们 不 匹 配 , 执 行 一 次 转 换 或 发 生 一 个 诊 断 消 息 。 参 数
也 经 历 常 用 的 算 术 转 换 。
在 表 达 式 表 中 的 表 达 式 个 数 必 须 与 参 数 个 数 相 匹 配 。 除 非 该 函 数 的 原 型或 定 义 显 式 指 出 参 量 个 数 是 可 变 的 , 在 这 种 情 况 下 , 编 译 器 检 测 参 数 表 中类 型 名 称 那 样 多 的 参 量 , 如 果 必 要 , 对 它 进 行 转 换 。 有 关 更 多 信 息 , 参 见 下一 节 的 “ 用 可 变 个 数 参 量 调 用 ”。
如 果 该 原 型 的 参 数 表 仅 包 含 关 键 字 void, 编 译 器 在 函 数 调 用 中 期 待 0 个参 量 , 在 定 义 中 期 待 0 个 参 数 。 如 果 发 现 了 任 何 参 量 , 编 译 器 发 出 一 个 诊断 消 息 。
例 子
这 个 例 子 使 用 指 针 作 为 参 量 :
void main()
{
/* 函数原型 */
void swap(int *num1,int *num2); int x,y;
.
.
.
swap(&x,&y); /* 函数调用 */
}
/* 函数定义 */
void swap(int *num1,int *num2)
{
int t;
t=*num1;
*num1=*num2;
*num2=t;
}
在 这 个 例 子 中 ,swap 函 数 在 main 中 说 明 , 它 有 两 个 参 量 , 分 别 用 标 识 符num1 和 num2 表 示 , 两 个 都 是 int 值 的 指 针 。 在 原 型 定 义 中 参 量 num1 和num2 也 都 说 明 为 int 类 型 值 的 指 针 。
在 函 数 调 用 中 :
swap (&x,&y);
x 的 地 址 存 储 在 num1 中 ,y 的 地 址 存 储 在 num2 中 ,现 在 在 同 样 的 位 置 存在 两 个 名 称 或 “ 别 名 ”。 swap 中 *num1 和 *num2 的 引 用 有 效 地 引 用 main 中 的 x 和 y 。 swap 中 的 赋 值 实 际 上 交 换 x 和 y 的 内 容 。 因 此 ,不 必 要 使用 return 语 句 。
编 译 器 在 swap 的 参 量 上 执 行 类 型 检 测 ,swap 的 原 型 包 括 每 个 参 数 的 参量 类 型 。 在 该 原 型 和 定 义 中 圆 括 号 中 的 标 识 符 可 以 是 相 同 或 不 相 同 的 。重 要 的 是 在 原 型 和 定 义 中 参 量 的 类 型 必 须 与 参 数 其 中 的 类 型 相 匹 配 。
用 可 变 个 数 参 量 调 用
部 分 参 数 表 可 以 通 过 省 略 标 记 终 止 。 一 个 逗 号 后 跟 三 个 句 点 (,...) 指 出 可以 有 更 多 的 参 量 传 送 给 函 数 , 但 它 们 没 有 给 出 更 多 信 息 。 类 型 检 测 不 是在 每 个 参 量 上 执 行 。 在 省 略 标 识 的 前 面 必 须 至 少 有 一 个 参 数 , 省 略 标 记必 须 是 参 数 表 中 最 后 一 个 语 言 符 号 。 没 有 省 略 标 记 , 如 果 它 接 受 除 了 参数 表 中 说 明 的 参 数 外 的 参 数 时 ,该 函 数 的 行 为 是 不 确 定 的 。
为 了 用 一 个 可 变 个 数 的 参 量 调 用 一 个 函 数 , 在 函 数 调 用 中 简 单 地 指 出 任何 个 数 的 参 量 。
一 个 例 子 是 C 运 行 库 的 printf 函 数 , 该 函 数 调 用 对 于 参 数 表 或 参 量 类 型中 说 明 的 每 个 类 型 名 称 必 须 包 含 一 个 参 量 。
在 函 数 调 用 中 指 定 的 所 有 参 量 都 放 在 栈 中 ,除 非 指 定 __ fastcall 调 用 约 定 。函 数 说 明 的 参 数 个 数 确 定 从 栈 中 取 多 少 参 量 并 赋 给 这 些 参 数 。 你 要 负 责从 栈 中 接 受 任 何 另 外 的 参 量 并 确 定 出 现 多 少 参 量 。 STDARGS.H 文 件 包含 访 问 具 有 可 变 参 量 个 数 的 函 数 的 参 量 的 ANSI 方 式 宏 。
同 样 , 也 支 持 包 含 在 VARARGS.H 中 的 XENIX 方 式 宏 。这 个 样 本 说 明 是 一 个 调 用 可 变 参 量 个 数 的 函 数 :
int averagc(int first,...)
Microsoft 特 殊 处 →
为 了 维 护 与 M icrosoft C 以 前 版 本 的 兼 容 性 ,ANSI C 标 准 的 一 个 M icrosoft 扩 充 是 允 许 参 数 表 的 末 尾 有 一 个 没 有 句 点 的 逗 号 (,) 指 出 可 变 的 参 量 个数 。 但 建 议 把 这 个 代 码 改 变 为 加 上 省 略 标 记 。
Microsoft 特 殊 处 结 束
递 归 函 数
在 C 程 序 中 的 任 何 函 数 可 以 递 归 调 用 ,也 就 是 ,它 可 以 调 用 本 身 。 递 归 调用 的 次 数 受 限 于 栈 的 尺 寸 。 有 关 设 置 栈 尺 寸 的 链 接 器 选 项 的 信 息 , 参 见联 机 “ M icrosoft Visual C++ 6.0 程 序 员 指 南 ” 中 的 “ 栈 分 配 ” (/STACK) 链 接 器 选 项 。 每 次 调 用 该 函 数 时 ,为 其 参 数 和 auto 及 register 变 量 分 配 新的 存 储 以 便 它 们 前 面 的 未 完 成 的 调 用 不 被 覆 盖 。 参 数 只 能 直 接 访 问 建 立它 们 的 函 数 的 实 例 。 以 前 的 参 数 不 能 直 接 访 问 后 面 的 函 数 实 例 。
注 意 有 static 存 储 说 明 的 变 量 在 每 次 递 归 调 用 时 不 需 要 新 的 存 储 。 它 们的 存 储 存 在 于 程 序 的 生 存 期 中 , 这 样 的 变 量 的 每 次 引 用 都 访 问 相 同 的 存储 区 域 。
例 子
这 个 例 子 说 明 了 递 归 调 用 :
int factorial(int num);/* 函数原型 */
void main()
{
int result,number;
.
.
.
result=factorial(number);
}
int factorial(int num) /* 函数定义 */
{
.
.
.
if ((num>0) || (num<=10)) return (num*factorial(num-1));
}
附 录 A C 语 言 语 法 总 结
本 附 录 给 出 了 C 语 言 和 Microsoft C 语 言 特 征 的 完 整 描 述 。 你 可 以 使 用 本 附 录中 的 说 明 确 定 任 何 语 言 组 成 成 分 的 准 确 语 法 。 在 本 手 册 讨 论 主 题 的 章 节 中 解 释了 本 节 出 现 的 语 法 。
注 意 : 这 个 语 法 总 结 不 是 ANSI C 标 准 部 分 , 仅 包 括 它 的 信 息 。 Microsoft 特 殊 的语 法 在 后 面 语 法 的 注 释 中 作 了 说 明 。
定 义 和 约 定
终 结 符 是 语 法 定 义 中 的 终 点 , 不 可 能 有 其 它 分 解 。 终 结 符 包 括 一 组 保 留 字 和 用 户定 义 标 识 符 。
非 终 结 符 在 语 法 中 是 位 置 占 用 者 , 在 这 个 语 法 总 结 中 的 其 它 地 方 定 义 。 定 义 可 以是 递 归 的 。
一 个 任 选 的 组 成 成 分 可 以 通 过 加 上 opt 下 标 来 指 出 , 例 如
{ 表 达 式 opt}
指 出 在 花 括 号 中 括 起 一 个 任 选 的 表 达 式 。
语 法 约 定 对 语 法 的 不 同 组 成 成 分 使 用 不 同 的 字 体 属 性 , 其 符 号 和 字 体 如 下 :
属 性 说明
非 终 结 符 斜 体 类 型 指 出 非 终 结 符
const 粗 体 类 型 的 终 结 符 是 必 须 输 入 的 保 留 字 和 符 号 。 在 这个 上 下 文 中 的 字 符 总 是 大 小 写 敏 感 的
opt 后 有 带 有 opt 的 非 终 结 符 总 是 任 选 的
缺 省 字 体 以 这 种 字 体 描 述 或 列 出 的 字 符 可 以 作 为 C 语 句 中 的 终结 符
- 个 非 终 结 符 后 跟 一 个 冒 号 (:) 指 出 它 的 定 义 。 另 一 种 定 义 以 分 行 形 式 列 出 , 除了 前 有 “ 如 下 之 一 ” 的 词 外 。
词 法
-
语 言 符 号
-
关 键 字
-
标 识 符
-
常 量
-
字 符 串 文 字
-
运 算 符
-
标 点
语 言 符 号 总 结
语 言 符 号 :
关 键 字
标 识 符
常量
字 符 串 文 字
运 算 符
标点
预 处 理 器 语 言 符 号 :
头 名 称
标 识 符
pp 数
字 符 常 量
字 符 串 文 字
运 算 符
标点
每 个 不 是 上 述 之 一 的 非 空 白 字 符头 名 称 :
< 路 径 指 示 符 >
“ 路 径 指 示 符 ” 路 径 指 示 符 :
合 法 的 文 件 路 径pp 数 :
数字
. 数 字
pp 数 数字
pp 数 非 数 字
pp 数 e 符 号
pp 数 E 符 号
pp 数 .
关 键 字 总 结
关 键 字 : 如 下 之 一
auto |
double |
int |
struct |
---|---|---|---|
break |
else |
long |
switch |
case |
enum |
register |
typedef |
char |
extern |
return |
union |
const |
float |
short |
unsigned |
continue |
for |
signed |
void |
default |
goto |
sizeof |
volatile |
do |
if |
static |
while |
标 识 符 总 结
标 识 符 :
非 数 字
标 识 符 非 数 字
标 识 符 数 字非 数 字 : 如 下 之 一
_ a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M N
O P Q R S T U V W X Y Z 数 字 : 如 下 之 一
0 1 2 3 4 5 6 7 8 9
常 量 总 结
常 量 :
浮 点 常 量
整 数 常 量
枚 举 常 量
字 符 常 量浮 点 常 量 :
分 数 常 量 指 数 部 分 opt 浮 点 后 缀 opt
数 字 序 列 指 数 部 分 浮 点 后 缀 opt
分 数 常 量 :
数 字 序 列 opt. 数 字 序 列
数 字 序 列指 数 部 分 :
e 符 号 opt 数 字 序 列
E 符 号 opt 数 字 序 列符 号 : 如 下 之 一 :
+ - 数 字 序 列 :
数字
数 字 序 列 数字浮 点 后 缀 : 如 下 之 一 :
f l F L 整 数 常 量 :
十 进 制 常 量 整 数 后 缀 opt
八 进 制 常 量 整 数 后 缀 opt
十 六 进 制 常 量 整 数 后 缀 opt
十 进 制 常 量 :
非 0 数 字
十 进 制 常 量 数 字八 进 制 常 量 :
0
八 进 制 常 量 八 进 制 数 字十 六 进 制 常 量 :
0x 十 六 进 制 常 量
0X 十 六 进 制 常 量
十 六 进 制 常 量 十 六 进 制 数 字非 0 数字 : 如 下 之 一
1 2 3 4 5 6 7 8 9 八 进 制 数 字 : 如 下 之 一
0 1 2 3 4 5 6 7 十 六 进 制 数 字 : 如 下 之 一
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
无 符 号 后 缀 : 如 下 之 一
u U
长 整 数 后 缀 : 如 下 之 一
l L 字 符 常 量 :
'c 字 符 序 列 '
L'c 字 符 序 列 ' 整 数 后 缀 :
无 符 号 后 缀 长 整 数 后 缀 opt
长 整 数 后 缀 无 符 号 后 缀 opt
c 字 符 :
源 字 符 集 中 除 单 引 号 (') 、 反 斜 杠 (\) 或 换 行 符 外 的 任 何 成 员
转 义 序 列转 义 序 列 :
简 单 转 义 序 列
八 进 制 转 义 序 列
十 进 制 转 义 序 列
简 单 转 义 序 列 , 如 下 之 一 :
\a \b \f \n \r \t \v
\ ′ \" \\ \? 八 进 制 转 义 序 列 :
\ 八 进 制 数 字
\ 八 进 制 数 字 八 进 制 数 字
\ 八 进 制 数 字 八 进 制 数 字 八 进 制 数 字十 六 进 制 转 义 序 列 :
\x 十 六 进 制 数 字
十 六 进 制 转 义 序 列 十 六 进 制 数 字
字 符 串 文 字 总 结
字 符 串 文 字 :
"s 字 符 序 列 opt"
L"s 字 符 序 列 opt" s 字 符 序 列 :
s 字 符
s 字 符 序 列 s 字 符s 字 符 :
源 字 符 集 中 除 双 引 号 (") 、 反 斜 杠 (\) 或 换 行 符 外 的 任 何 成 员
转 义 序 列
运 算 符
运 算 符 : 如 下 之 一
[ ] ( ) . ->
++ -- & * + - ~ ! sizeof
/ % << >> < > <= >= == != ^ | && !!
? :
= *= /= %= += -= <<= >>= &= ^= |=
, # ##
赋 值 运 算 符 : 如 下 之 一
= *= /= %= += -= <<= >>= &= ^= |=
标 点
标 点 : 如 下 之 一
[ ] ( ) { } * , : = ; ... #
短 语 结 构 语 法
-
表 达 式
-
说 明
-
语 句
-
外 部 定 义
表 达 式 总 结
基 本 表 达 式
标 识 符
常量
字 符 串 文 字
( 表 达 式 ) 表 达 式 :
赋 值 表 达 式
表 达 式 , 赋 值 表 达 式
常 量 表 达 式 :
条 件 表 达 式条 件 表 达 式 :
逻辑 OR 表 达 式
逻辑 OR 表 达 式 ? 表 达 式 : 条 件 表 达 式赋 值 表 达 式 :
条 件 表 达 式
单 目 表 达 式 赋 值 运 算 符 赋 值 表 达 式后 缀 表 达 式 :
基 本 表 达 式
后 缀 表 达 式 [ 表 达 式 ]
后 缀 表 达 式 ( 参 量 表 达 式 表 opt )
后 缀 表 达 式 . 标 识 符
后 缀 表 达 式 -> 标 识 符
后 缀 表 达 式 ++
后 缀 表 达 式 -- 赋 值 表 达 式 表 :
赋 值 表 达 式
赋 值 表 达 式 表 , 赋 值 表 达 式单 目 表 达 式 :
后 缀 表 达 式
++ 单 目 表 达 式
-- 单 目 表 达 式
单 目 表 达 式 造 型 表 达 式
sizeof 单 目 表 达 式
sizeof( 类 型 名 称 ) 单 目 表 达 式 : 如 下 之 一
& * + - ~ ! 造 型 表 达 式 :
单 目 表 达 式
( 类 型 名 称 ) 造 型 表 达 式乘 法 表 达 式 :
造 型 表 达 式
乘 法 表 达 式 * 造 型 表 达 式
乘 法 表 达 式 / 造 型 表 达 式
乘 法 表 达 式 % 造 型 表 达 式加 法 表 达 式 :
乘 法 表 达 式
加 法 表 达 式 + 乘 法 表 达 式
加 法 表 达 式 - 乘 法 表 达 式位 移 表 达 式 :
加 法 表 达 式
位 移 表 达 式 << 加 法 表 达 式
位 移 表 达 式 >> 加 法 表 达 式
关 系 表 达 式 :
位 移 表 达 式
关 系 表 达 式 < 位 移 表 达 式
关 系 表 达 式 > 位 移 表 达 式
关 系 表 达 式 <= 位 移 表 达 式
关 系 表 达 式 >= 位 移 表 达 式相 等 表 达 式 :
关 系 表 达 式
相 等 表 达 式 == 关 系 表 达 式
相 等 表 达 式 != 关 系 表 达 式AND 表 达 式 :
相 等 表 达 式
AND 表 达 式 & 相 等 表 达 式异 或 表 达 式 :
AND 表 达 式
异 或 表 达 式 ^ AND 表 达 式或 表 达 式 :
异 或 表 达 式
或 表 达 式 | 异 或 表 达 式逻 辑 AND 表 达 式 :
或 表 达 式
逻辑 AND 表 达 式 && 或 表 达 式
逻 辑 OR 表 达 式 :
逻辑 AND 表 达 式
逻辑 OR 表 达 式 || 逻 辑 AND 表 达 式
说 明 总 结
说 明 :
说 明 指 示 符 属 性 序 列 opt 初 始 说 明 符 表 opt ;
/* 属 性 序 列 是 Microsoft 特 殊 处 */ 说 明 指 示 符 :
存 储 类 指 示 符 说 明 指 示 符 opt
类 型 指 示 符 说 明 指 示 符 opt
类 型 修 饰 符 说 明 指 示 符 opt
属 性 序 列 :/* 属 性 序 列 是 Microsoft 特 殊 处 */
属性 属 性 序 列 opt
属性 : 如 下 之 一 /* Microsoft 特 殊 处 */
__ asm fastcall
__ based inline
__ cdecl stdcall
初 始 说 明 符 表 :
初 始 说 明 符
初 始 说 明 符 表 , 初 始 说 明 符初 始 说 明 符 :
初 始 说 明 符
初 始 说 明 符 = 初 始 化 器 /* 对 于 标 量 初 始 化 */ 存 储 类 指 示 符 :
auto
register
static
extern
typedef
__ declspec( 扩 充 的 说 明 修 饰 符 序 列 ) /* Microsoft 特 殊 处 */ 类 型 指 示 符 :
void
char
short
int
__ int8 /* Microsoft 特 殊 处 */
__ int16 /* Microsoft 特 殊 处 */
__ int32 /* Microsoft 特 殊 处 */
__ int64 /* Microsoft 特 殊 处 */
long
float
double
signed
unsigned
结 构 或 联 合 指 示 符
枚 举 指 示 符
typedef 名 称类 型 修 饰 符 :
const
volatile 说 明 符 :
指针 opt 直 接 说 明 符直 接 说 明 符 :
标 识 符
( 说 明 符 )
直 接 说 明 符 [ 常 量 表 达 式 opt ]
直 接 说 明 符 ( 参 数 类 型 表 ) /* 新 式 说 明 符 */
直 接 说 明 符 ( 标 识 符 表 opt ) /* 己 废 除 的 说 明 符 */ 指 针 :
* 类 型 修 饰 符 表 opt
* 类 型 修 饰 符 表 opt 指针参 数 类 型 表 : /* 参 数 表 */
参 数 表
参 数 表 ,... 参 数 表 :
参 数 说 明
参 数 表 , 参 数 说 明类 型 修 饰 符 表 :
类 型 修 饰 符
类 型 修 饰 符 表 类 型 修 饰 符枚 举 指 示 符 :
enum 标 识 符 opt { 枚 举 器 表 }
enum 标 识 符枚 举 器 表 :
枚 举 器
枚 举 器 表 , 枚 举 器枚 举 器 :
枚 举 常 量
枚 举 常 量 = 常 量 表 达 式枚 举 常 量 :
标 识 符
结 构 或 联 合 指 示 符 :
结 构 或 联 合 标 识 符 opt { 结 构 说 明 表 }
结 构 或 联 合 标 识 符结 构 或 联 合 :
struct
union
结 构 说 明 表 :
结 构 说 明
结 构 说 明 表 结 构 说 明结 构 说 明 :
指 示 符 修 饰 符 表 结 构 说 明 表指 示 符 修 饰 符 表 :
类 型 指 示 符 指 示 符 修 饰 符 表 opt
类 型 修 饰 符 指 示 符 修 饰 符 表 opt
结 构 说 明 符 表 :
结 构 说 明 符
结 构 说 明 符 表 , 结 构 说 明 符结 构 说 明 符 :
说 明 符
类 型 指 示 符 说 明 符 opt : 常 量 表 达 式参 数 说 明 :
说 明 指 示 符 说 明 符 /* 命 名 的 说 明 符 */
说 明 指 示 符 抽 象 说 明 符 opt /* 无 名 称 的 说 明 符 */ 标 识 符 表 : /* 对 于 旧 式 说 明 符 */
标 识 符
标 识 符 表 , 标 识 符
抽 象 说 明 符 : /* 与 无 名 称 的 说 明 符 一 起 使 用 */
指针
指针 opt 直 接 抽 象 说 明 符直 接 抽 象 说 明 符 :
( 抽 象 说 明 符 )
直 接 抽 象 说 明 符 opt [ 常 量 表 达 式 opt ]
直 接 抽 象 说 明 符 opt ( 参 数 类 型 表 opt ) 初 始 化 器 :
赋 值 表 达 式
{ 初 始 化 器 表 } /* 对 于 集 合 的 初 始 化 */
{ 初 始 化 器 表 ,} 初 始 化 器 表 :
初 始 化 器
初 始 化 器 表 , 初 始 化 器类 型 名 称 :
指 示 符 修 饰 符 表 抽 象 说 明 符 opt
typedef 名 称 :
标 识 符
扩 充 的 说 明 符 修 饰 符 序 列 : /* Microsoft 特 殊 处 */
扩 充 的 说 明 符 修 饰 符 opt
扩 充 的 说 明 符 修 饰 符 序 列 扩 充 的 说 明 符 修 饰 符
扩 充 的 说 明 符 修 饰 符 : /* Microsoft 特 殊 处 */
thread
naked
dllimport
dllexport
语 句 总 结
语 句 :
标 号 语 句
复 合 语 句
表 达 式 语 句
选 择 语 句
迭 代 语 句
跳 转 语 句
try-except 语 句 /* Microsoft 特 殊 处 */
try-finally 语 句 /* Microsoft 特 殊 处 */ 跳 转 语 句 :
goto 标 识 符 ;
continue;
break;
return 表 达 式 opt ; 复 合 语 句 :
{ 说 明 表 opt 语 句 表 opt } 说 明 表 :
说明
说 明 表 说 明语 句 表 :
语句
语 句 表 语 句表 达 式 语 句 :
表 达 表 opt; 迭 代 语 句 :
while ( 表 达 式 ) 语 句
do 语 句 while ( 表 达 式 )
for ( 表 达 式 opt ; 表 达 式 opt ; 表 达 式 opt ) 语 句选 择 语 句 :
if ( 表 达 式 ) 语 句
if ( 表 达 式 ) 语 句 else 语 句
switch ( 表 达 式 ) 语 句标 号 语 句 :
标 识 符 : 语 句
case 常 量 表 达 式 : 语 句
default : 语句
try-except 语 句 : /* Microsoft 特 殊 处 */
__ try 复 合 语 句
__ except ( 表 达 式 ) 复 合 语 句
try-finally 语 句 : /* Microsoft 特 殊 处 */
__try 复 合 语 句
__finally 复 合 语 句
外 部 定 义
转 换 单 元 :
外 部 说 明
转 换 单 元 外 部 说 明
外 部 说 明 : /* 仅 允 许 在 外 部 ( 文 件 ) 范围 */
函 数 定 义
说明
函 数 定 义 : /* 这 里 的 说 明 符 是 函 数 说 明 符 */ 说 明 指 示 符 opt 说 明 符 说 明 表 opt 复 合 语 句