第 2 章 程 序 结 构
本 章 给 出 C 程 序 和 程 序 执 行 的 一 个 概 述 , 也 介 绍 了 理 解 C 程 序 和 组 成 成 分 的 重 要术 语 和 特 征 。 讨 论 的 主 题 包 括 :
-
源 文 件 和 源 程 序
-
main 函 数 和 程 序 执 行
-
命 令 行 参 量 分 析
-
生 存 期 、 范 围 、 可 见 性 和 连 接
-
名 称 空 间
因 为 本 章 是 概 述 , 讨 论 的 主 题 仅 包 括 一 些 引 言 材 料 , 有 关 详 细 解 释 参 见 交 叉 引 用的 信 息 。
源 文 件 和 源 程 序
一 个 源 程 序 可 以 分 成 一 个 或 多 个 “ 源 文 件 ” 或 “ 转 换 单 元 ”。 输 入 到 编 译 器 被 称为 一 个 “ 转 换 单 元 ”。
语 法
转 换 单 元 :
外 部 说 明
转 换 单 元 外 部 说 明外 部 说 明 :
函 数 定 义
说明
第 3 章 “ 说 明 和 类 型 ” 中 的 “ 说 明 概 述 ” 给 出 了 说 明 非 终 结 符 的 语 法 , 本 卷 后 面的 “ 预 处 理 器 参 考 ” 解 释 了 如 何 处 理 转 换 单 元 。
注 意 : 有 关 ANSI 语 法 规 则 的 解 释 , 参 见 本 卷 后 面 的 附 录 A “ C 语 言 语 法 总 结 ” 的引 言 。
-
个 转 换 单 元 的 组 成 成 分 是 包 括 函 数 定 义 和 标 识 符 说 明 的 外 部 说 明 。 这 些 说 明和 定 义 可 以 在 源 文 件 、 头 文 件 、 库 和 该 程 序 需 要 的 其 它 文 件 中 , 你 必 须 编 译 每 个转 换 单 元 并 链 接 产 生 的 目 标 文 件 来 生 成 一 个 程 序 。
-
个 C “ 源 程 序 ” 是 命 令 、 编 译 指 示 、 说 明 、 定 义 、 语 句 块 和 函 数 组 成 的 , 为 了使 一 个 Microsoft C 程 序 生 效 , 每 一 个 组 成 成 分 必 须 具 有 本 书 中 描 述 的 语 法 , 虽然 它 们 可 以 以 任 何 次 序 放 在 程 序 中 ( 服 从 本 书 描 绘 的 规 则 ) 。 但 这 些 组 成 成 分 在一 个 程 序 中 的 位 置 不 影 响 一 个 程 序 中 使 用 的 变 量 和 函 数 ( 有 关 更 多 信 息 , 参 见 本章 后 面 的 “ 生 存 期 、 范 围 、 可 见 性 和 连 接 ” ) 源 文 件 不 需 要 包 含 可 执 行 语 句 , 例如 , 你 可 能 发 现 这 种 方 式 是 有 用 的 , 在 一 个 源 文 件 中 放 置 变 量 的 定 义 , 然 后 在 另 一个 源 文 件 说 明 引 用 这 些 变 量 。 这 种 技 术 很 容 易 找 到 和 修 改 定 义 , 同 样 的 理 由 , 常量 和 宏 经 常 组 成 称 为 “ 包 括 文 件 ” 或 “ 头 文 件 ” 的 分 开 文 件 中 , 需 要 时 在 源 文 件中 引 用 它 们 , 有 关 宏 和 包 括 文 件 的 信 息 , 参 见 本 卷 后 面 的 “ 预 处 理 器 参 考 ”。
预 处 理 器 的 命 令
一个 “命令”指示 C 预处理器在编译之前对程序文本执行特定动作。预处理器命令 在 本 卷 后 面 的 “ 预 处 理 器 参 考 ” 中 进 行 充 分 的 描 述 , 本 例 使 用 预 处 理 器 命 令#define:
#define MAX 100
这 个 语 句 告 诉 编 译 器 在 编 辑 之 前 将 MAX 的 每 次 出 现 均 用 100 替 换 。 C 编 译 器 预处 理 器 命 令 是 :
#define |
#endif |
#ifdef |
#line |
---|---|---|---|
#elif |
#error |
#ifndef |
#pragma |
#else |
#if |
#include |
#undef |
编 译 指 示
Microsoft 特 殊 处 →
- 个 “ 编 译 指 示 ” 指 示 编 译 器 在 编 译 时 执 行 一 个 特 殊 动 作 。 编 译 指 示 从 编 译 器到 编 译 器 时 发 生 改 变 。 例 如 , 你 可 以 使 用 optimize 编 译 指 示 设 置 你 的 程 序 要 执行 的 优 化 。 Microsoft C 编 译 指 示 有 :
alloc_text data_seg inline_recurs
ion
setlocale
auto_inline function intrinsic warning check_stack hdrstop message
code_seg include_alias ptimize
comment inline_depth pack
有 关 Microsoft C 编 译 器 编 译 指 示 的 描 述 参 见 本 卷 后 面 “ 预 处 理 器 参 考 ” 中 的 第 2 章 “ 编 译 指 示 命 令 ”。
Microsoft 特 殊 处 结 束
说 明 和 定 义
- 个 “ 说 明 ” 在 一 个 特 定 变 量 、 函 数 或 类 型 及 其 属 性 之
间 建 立 关 联 。 第
3 章 “ 说 明 和 类 型 ” 中 的 “ 说 明 概 述 ” 给 出 了 说 明 非 终 结 符 的 ANSI 语法 ,一 个 说 明 也 指 出 访 问 一 个 标 识 符 的 地 方 和 时 间 ( 标 识 符 的 “ 连 接 ” )。有 关 连 接 的 信 息 参 见 本 章 后 面 的 “ 生 存 期 、 范 围 、 可 见 性 和 连 接 ”。
- 个 变 量 的 “ 定 义 ” 建 立 与 说 明 相 同 的 关 联 , 它 还 导 致 分 配 该 变 量 的 存储 。
例 如 ,main 、 find 和 count 函 数 以 及 var 和 val 变 量 都 依 次 定 义 在 一 个 源文 件 中 :
void main()
{
}
int var=0;
double val[MAXVAL]; char find(fileptr)
{
}
int count(double f)
{
}
变 量 var 和 val 用 于 find 和 count 函 数 中 , 不 需 要 进 一 步 的 说 明 ,但 它 们 的名 字 在 main 中 是 不 可 见 的 ( 不 能 访 问 )。
函 数 说 明 和 定 义
函 数 原 型 建 立 该 函 数 的 名 称 、 其 返 回 值 、 它 的 形 参 的 类 型 和 个 数 。 一 个函 数 定 义 包 括 函 数 体 。
函 数 和 变 量 说 明 可 以 出 现 在 一 个 函 数 定 义 的 内 部 或 外 部 。 一 个 函 数 定 义中 的 任 何 说 明 称 为 “ 内 部 的 ” 或 “ 局 部 的 ”。 所 有 函 数 定 义 外 部 的 说 明称 为 “ 外 部 的 ”、“ 全 局 的 ” 或 “ 文 件 范 围 ”。 变 量 定 义 像 说 明 一 样 , 可 以在 内 部 层 ( 一 个 函 数 定 义 内 部 ) 或 外 部 层 ( 所 有 函 数 的 外 部 ) 中 进 行 。 函 数定 义 总 是 出 现 在 外 部 层 。函 数 定 义 的 进 一 步 讨 论 在 第 6 章“ 函 数 ”的“ 函数 定 义 ” 中 。 函 数 原 型 在 第 6 章 的 “ 函 数 原 型 ” 中 讨 论 。
块
用 花 括 号 ({} )括 起 来 的 说 明 、 定 义 和 语 句 序 列 称 为 一 个 “ 块 ”。 C 中 有 两种 类 型 的 块 。 复 合 语 句 是 一 个 或 多 个 语 句 组 成 的 语 句 ( 参 见 第 5 章 “ 语
句 ” 中 的 “ 复 合 语 句 ” ),它 是 一 种 类 型 的 块 。 另 一 种 类 型 的 块 是 “ 函 数定 义 ” , 它 由 一 个 复 合 语 句 ( 函 数 体 ) 加 上 该 函 数 关 联 的 “ 头 ” ( 该 函 数 名称 、 返 回 类 型 和 形 参 )。 一 个 块 中 的 另 一 个 块 称 之 为 “ 嵌 套 ”。
注 意 , 所 有 复 合 语 句 都 是 用 花 括 号 括 起 来 的 , 但 并 不 是 花 括 号 中 的 任 何东 西 都 组 成 一 个 复 合 语 句 , 例 如 , 数 组 、 结 构 或 枚 举 元 素 的 规 格 都 出 现 在花 括 号 中 ,但 它 们 不 是 复 合 语 句 。
例 子 程 序
如 下 C 源 程 序 由 两 个 源 文 件 组 成 , 它 给 出 一 个 C 程 序 中 各 种 可 能 的 说 明和 定 义 的 概 述 。 本 书 后 面 的 章 节 讨 论 如 何 编 写 这 些 说 明 、 定 义 和 初 始 化 , 以 及 如 何 使 用 C 关 键 词 如 static 和 extern 。printf 函 数 在 C 头 文 件 STDIO.H 中 说 明 。
main 和 max 函 数 假 设 在 分 开 的 文 件 中 ,程 序 的 执 行 从 main 函 数 开 始 。在 main 之 前 不 会 显 式 执 行 用 户 函 数 。
/********************************************************* FILE1.C - main function
**********************************************************/ #define ONE 1
#define TWO 2
#define THREE 3 #include <stdio.h>
int a=1; / * 定义外部变量的说明 */ int b=2;
extern int max(int a,int b); / * 函数原型 */
int main() / *main 函数的函数定义 */
{
int c; / * 两个未初始化的局部变量的定义 */ int d;
extern int u; / * 重 新 引 用 其 它 地 方 定 义 的 外 部 变 量 的 说 明
*/
static int v; / * 定义具有连续生存期的变量 */
int w=ONE,x=TWO,y=THREE;
int z=0;
z=max(x,y); /* 可执行的语句 */ w=max(z,w);
printf("%d %d\n",z,w); return 0;
}
/*********************************************************
FILE2.C - defination of max function
**********************************************************/ int max(int a,int b) /* 注意形式参数包括在函数头中 */
{
if (a>b)
return(a); else
return(b);
}
FILE1.C 包 含 max 函 数 的 原 型 , 这 种 说 明 有 时 称 为 “ 前 向 说 明 ” ,因 为 在该 函 数 使 用 之 前 说 明 。 main 函 数 的 定 义 包 括 调 用 max 。
以 #define 开 头 的 行 是 预 处 理 器 命 令 。 这 些 命 令 告 诉 编 译 器 在 FILE1.C 中 分 别 用 1 、 2 和 3 替 换 标 识 符 ONE 、 T W O 和 THREE 。 以 #include 开头 的 行 告 诉 编 译 器 包 括 文 件 STDIO.H ,它 包 含 printf 函 数 的 原 型 。 预 处理 器 命 令 在 本 卷 后 面 的 “ 预 处 理 器 参 考 ” 中 解 释 。
FILE1.C 使 用 定 义 说 明 来 初 始 化 全 局 变 量 a 和 b ,局 部 变 量 c 和 d 说 明 了但 未 初 始 化 。 所 有 这 些 变 量 都 分 配 了 存 储 。 静 态 和 外 部 变 量 u 和 v 都 自动 初 始 化 为 0 。 因 此 在 说 明 时 只 有 a 、 b 、 u 和 v 包 含 有 意 义 的 值 , 因 为 它们 显 式 或 隐 含 地 初 始 化 。 F1LE2.C 包 含 max 的 函 数 定 义 。 这 个 定 义 满足 在 FILE1.C 中 调 用 max 。
标 识 符 的 生 存 期 和 可 见 性 在 本 章 后 面 的“ 生 存 期 、 范 围 、 可 见 性 和 连 接 ” 中 讨 论 。 有 关 函 数 的 更 多 信 息 ,参 见 第 6 章 “ 函 数 ”。
main 函 数 和 程 序 执 行
每 个 C 程 序 有 一 个 必 须 命 名 为 main 的主 (main) 函 数 。 如 果 你 的 代 码 服从 单 代 码 程 序 设 计 模 式 ,你 可 以 使 用 main 的 宽 字 符 版 本 wmain 。 main 函数 作 为 程 序 执 行 的 起 始 点 。 通 常 通 过 在 程 序 中 调 用 其 它 函 数 来 控 制 程 序的 执 行 。 一 个 程 序 执 行 到 main 的 末 尾 会 终 止 , 但 它 可 以 由 于 各 种 原 因 在其 它 程 序 的 地 方 终 止 。 这 时 可 能 检 测 到 某 个 错 误 , 你 要 强 制 一 个 程 序 终止 ,为 此 ,要 使 用 exit 函 数 。有 关 使 用 exit 函 数 的 例 子 和 信 息 参 见“ Microsoft Visual C++ 6.0 参 考 库 ” 的 “ M icrosoft Visual C++ 6.0 运 行 库 参 考 ” 卷 。在 源 程 序 中 的 函 数 实 现 一 个 或 多 个 特 定 功 能 。 main 函 数 调 用 这 些 函 数实 现 它 们 的 各 自 功 能 。 当 main 调 用 另 一 函 数 时 , 它 把 执 行 控 制 传 给 该 函数 , 因 此 从 该 函 数 的 第 一 个 语 句 开 始 执 行 。 当 执 行 return 语 句 或 到 达 该函 数 的 末 尾 时 , 把 控 制 返 回 给 main 。
你 可 以 说 明 任 何 函 数 包 括 main 所 具 有 的 参 数 。 术 语 “ 参 数 ” 或 “ 形 参 ” 指 的 是 接 受 一 个 传 给 该 函 数 的 值 的 标 识 符 。 有 关 传 送 参 量 给 参 数 的 信 息参 见 第 6 章 “ 函 数 ” 中 的 “ 参 数 ”。 当 一 个 函 数 调 用 另 一 个 函 数 时 ,被 调用 函 数 从 调 用 函 数 获 取 它 的 参 数 值 , 这 些 值 称 为 “ 参 量 ”。 你 可 为 main 说 明 形 参 ,以 便 它 使 用 如 下 格 式 从 命 令 行 接 受 参 量 :
main(int argc ,char * argv [],char * envp [])
当 你 要 传 送 信 息 给 main 时 ,参 数 习 惯 上 命 名 为 argc 和 argv , 尽 管 C 编 译器 不 要 求 这 些 名 称 。 argc 和 argv 由 C 语 言 定 义 。 如 果 传 给 main 第 三 个参 数 , 习 惯 上 命 名 这 个 参 数 为 envp 。 本 章 后 面 的 例 子 说 明 了 如 何 使 用 这
三 个 参 数 访 问 命 令 行 参 量 。 下 面 小 节 解 释 这 些 参 数 。
有 关 main 宽 字 符 版 本 的 描 述 参 见 下 一 节 “ 使 用 wmain ”。
使 用 wmain
Microsoft 特 殊 处 →
在 单 代 码 程 序 设 计 模 式 中 , 你 可 以 定 义 main 函 数 的 宽 字 符 版 本 。 如 果 你要 编 写 服 从 单 代 码 程 序 设 计 模 式 的 可 移 植 代 码 , 则 使 用 wmain 代 替main 。
你 可 以 使 用 类 似 于 main 的 格 式 说 明 wmain 的 形 式 参 数 , 然 后 传 送 宽 字 符参 量 和 任 选 的 宽 字 符 环 境 指 针 给 该 程 序 。 wmain 的 argv 和 envp 参 数 是wchar_t * 类 型 ,例 如 :
wmain(int argc ,wchar_t *argv [],wchar_t *envp [])
如 果 你 的 程 序 使 用 一 个 main 函 数 , 通 过 运 行 库 在 启 动 程 序 时 建 立 多 字 节字 符 环 境 。 当 需 要 时 ( 例 如 调 用 _wgetenv 或 _wputenv 函 数 ) 只 建 立 该 环 境的 一 个 宽 字 符 拷 贝 。 如 果 一 个 MBCS 环 境 已 经 存 在 时 , 第 一 次 调 用
_wputenv 或 第 一 次 调 用 _wgetenv 时 ,则 建 立 对 应 的 宽 字 符 串 环 境 ,然 后 由
_wenviron 全 局 变 量 指 向 它 ,该 变 量 是 _environ 全 局 变 量 的 宽 字 符 版 本 。在 这 时 , 该 环 境 的 两 个 拷 贝 (MBCS 和 单 代 码 ) 同 时 存 在 , 并 且 由 操 作 系 统在 该 程 序 生 存 期 中 进 行 维 护 。
类 似 地 , 如 果 你 的 程 序 使 用 一 个 wmain 函 数 ,在 程 序 启 动 时 建 立 一 个 宽 字符 环 境 并 由 _wenviron 全 局 变 量 指 向 它 。 在 第 一 次 调 用 _putenv 或 getenv 时 建 立 一 个 MBCS(ASCII) 环 境 , 并 由 _environ 全 局 变 量 指 向 它 。 有 关
MBCS 环 境 更 多 的 信 息 , 参 见“ M icrosoft Visual C++ 参 考 库 ”的“ M icrosoft Visual C++6.0 运 行 库 参 考 ” 卷 。
Microsoft 特 殊 处 结 束参 量 描 述
main 和 wmain 函 数 的 argc 参 数 是 一 个 整 数 ,指 出 从 命 令 行 传 给 该 程 序 的参 量 个 数 ,由 于 程 序 名 称 也 作 为 一 个 参 量 考 虑 , argc 的 值 至 少 为 1 。
argv 参 数 是 一 个 表 示 程 序 参 量 的 以 空 格 结 尾 的 字 符 串 的 指 针 数 组 。 该 数组 的 每 个 元 素 指 向 一 个 传 给 main( 或 wmain) 的 参 量 的 字 符 串 ( 有 关 数 组的 信 息 , 参 见 第 3 章 “ 说 明 和 类 型 ” 中 的 “ 数 组 说 明 ” )。 argv 参 数 可 以作 为 一 个 类 型 char 的 指 针 数 组 (char *argv[]) 或 者 类 型 char 的 指 针 的 指 针(char **argv) 来 说 明 。 对 于 wmain ,argv 参 数 可 以 作 为 类 型 wchar_t 的 指针 数 组 (wchar_t *argv[]) 或 者 类 型 wchar_t 的 指 针 的 指 针 (wchar_t **argv) 来 说 明 。 第 一 个 字 符 串 (argv[0]) 是 程 序 名 称 , 最 后 指 针 (argv[argc]) 为NULL( 有 关 获 取 环 境 变 量 信 息 的 另 一 种 方 法 参 见 “ M icrosoft Visual C++6.0 运 行 库 参 考 ” 中 的 “ getenv ” )。
Microsoft 特 殊 处 →
envp 参 数 是 表 示 用 户 环 境 变 量 中 值 设 置 的 以 空 格 结 尾 的 字 符 串 的 数 组 的 指 针 。envp 参 数 可 以 说 明 为 char 的 一 个 指 针 数 组 (char *envp[]) 或 char 的 指 针 的 指针 (char **envp)。 在 wmain 函 数 中 , envp 参 数 可 以 说 明 为 wchar_t 的 指 针 数 组(wchar_t *invp[]) 或 wchar_t 的 指 针 的 指 针 (wchar_t **envp) 。 该 数 组 的 末 尾由 NULL * 指 针 指 向 。 注 意 , 传 给 main 或 wmain 的 环 境 块 是 当 前 环 境 的 一 个 “ 冻
结 的 ”拷 贝 。如 果 你 后 面 经 由 调 用 _putenv 或 _wputenv 改 变 该 环 境 , 当 前 环 境 ( 由getenv/_wgetenv 和 _environ 或 _wenviron 变 量 返 回 ) 将 改 变 , 但由 envp 所 指 的块 不 改 变 。 envp 参 量 在 C 中是 ANSI 兼 容 的 , 但 在 C++ 中 不 是 。
Microsoft 特 殊 处 结 束扩 充 通 配 符 参 量
Microsoft 特 殊 处 →
当 运 行 一 个 C 程 序 时 , 你 可 以 使 用 两 个 通 配 符 即 问 号 (?) 和 星 号 (*) 指 出 命 令 行 上的 文 件 名 和 路 径 参 量 。
命 令 行 参 量 由 一 个 称 为 _setargv( 在 宽 字 符 环 境 中 称 为 _wsetargv) 的 例 程 处 理 , 它 缺 省 地 不 扩 充 argv 字 符 串 数 组 中 的 通 配 符 为 分 离 的 字 符 串 。 你 可 以 使 用 一 个功 能 更 强 大 的 版 本 _setargv 通 过 与 setargv.obj 文 件 链 接 处 理 通 配 符 来 代 替 正常 的 _ setargv 。 如 果 你 的 程 序 使 用 一 个 wmain 函 数 , 则 与 wsetargv.obj 链 接 。为 了 与 setargv.obj 或 wsetargv.obj 链接 , 使 用 /link 选 项 , 例 如 :
c l typeit.c /link setargv.obj
该 通 配 符 与 操 作 系 统 命 令 中 的 同 样 方 式 进 行 扩 充 ( 如 果 你 不 熟 悉 该 通 配 符 , 参 见你 的 操 作 系 统 用 户 指 南 ) 。 在 双 引 号 中 括 起 一 个 参 量 阻 止 通 配 符 扩 充 。 在 一 个 括起 的 参 量 中 , 你 可 以 通 过 在 双 引 号 之 前 加 一 个 反 向 斜 杠 (\) 来 表 示 双 引 号 文 字 。如 果 该 通 配 符 参 量 没 有 找 到 匹 配 的 , 该 参 量 作 为 文 字 传 送 。
Microsoft 特 殊 处 结 束
命 令 行 参 量 的 分 析
Microsoft 特 殊 处 →
在 解 释 操 作 系 统 命 令 行 给 定 的 参 量 时 , M icrosoft C 启 动 代 码 使 用 如 下规 则 :
-
由 空 白 定 界 参 量 , 它 是 一 个 空 格 或 制 表 。
-
由 双 引 号 括 起 的 一 个 字 符 串 作 为 单 个 参 量 解 释 , 忽 略 其 中 包 含 的 空白 。 一 个 括 起 的 字 符 串 可 以 嵌 入 在 一 个 参 量 中 。 注 意 , 插 入 记 号 (^) 不 作 为 一 个 转 义 字 符 或 定 界 符 识 别 。
-
双 引 号 前 加 一 个 反 向 斜 杠 (\) 解 释 为 一 个 文 字 双 引 号 (") 。
-
反 向 斜 杠 作 为 文 字 解 释 的 , 除 非 它 们 直 接 跟 一 个 双 引 号 。
-
如 果 偶 数 个 反 向 斜 杠 后 跟 一 个 双 引 号 , 那 么 argv 数 组 中 的 每 对 反 向斜 杠 (\\) 用 一 个 反 向 斜 杠 代 替 , 且 将 双 引 号 (") 解 释 为 一 个 字 符 定 界符 。
-
如 果 奇 数 个 反 向 斜 杠 后 跟 一 个 双 引 号 , 那 么 和 argv 数 组 中 每 对 反 向斜 杠 (\\) 用 一 个 反 向 斜 杠 代 替 , 双 引 号 被 解 释 为 剩 下 的 一 个 反 向 斜杠 的 转 义 序 列 , 导 致 在 argv 中 放 置 一 个 文 字 双 引 号 (") 。
如 下 表 说 明 了 传 递 给 argv 几 个 命 令 行 参 量 例 子 的 解 释 结 果 ,列 出 的 第 2
列 、 第 3 列 和 第 4 列 的 结 果 来 自 后 面 的 ARGS.C 程 序 的 输 出 。
命令行输出 |
argv[1] |
argv[2] |
argv[3] |
---|---|---|---|
"a b c" d e |
a b c |
d |
e |
"ab\"c" "\\" d |
ab"c |
\ |
d |
a\\\b d"e f"g h a\\\b de fg |
h |
||
---|---|---|---|
a\\\"b c d |
a\"b |
c |
d |
a\\\\"b c" d e |
a\\b c |
d |
e |
/*ARGS.C 说明了如下用于访问命令行参量和环境变量 :
-
argc argvenvp
-
的变量
*/
#include <stdio.h>
void main(int argc, |
/* |
数组 argv 中的字符串的个数 */ |
---|---|---|
char *argv[], char **envp) |
/* 命令行参量字符串的数组 */ /* 环境变量字符串的数组 */ |
{
int count;
/* 显 示 每 个 命 令 行 参 量 */ printf("\nCommand-line arguments:\n"); for (count=0;count<argc;count++);
printf("argv[%d] %s\n",count,argv[count]);
/* 显示每个环境变量 */
printf("\nEnvironment variables:\n"); while (*envp!=NULL)
printf(" %s\n",*(envp++));
return;
}
这 个 程 序 的 一 个 输 出 例 子 如 下 :
Command-line arguments: argv[0] C:\MSC\TEST.EXE
Environment variables: COMSPEC=C:\NT\SYSTEM32\CMD.EXE
PATH=c:\nt;c:\binb;c:\binr;c:\nt;c:\system32;c:\word;c:\help;c:\msc;c:\; PROMPT=[$p]
TEMP=c:\tmp TMP=c:\tmp EDITORS=c:\binr WINDIR=c:\nt
Microsoft 特殊处结束
定 制 命 令 行 处 理
如 果 你 的 程 序 不 用 命 令 行 参 量 , 你 可 以 通 过 阻 止 使 用 实 现 命 令 行 处 理 的例 程 来 节 省 一 些 空 间 , 这 个 例 程 称 为 _setargv( 在 宽 字 符 环 境 中 为
_wsetargv), 正 如 本 章 前 面 “ 扩 充 通 配 符 参 量 ” 中 描 述 的 。 为 了 阻 止 它 的使 用 , 在 包 含 main 函 数 的 文 件 中 定 义 一 个 不 做 任 何 事 情 的 例 程 , 也 取 名 为
_setargv( 在 宽 字 符 环 境 中 为 _wsetargv) 。 那 么 调 用 _setargv 或 _wsetargv
满 足 你 定 义 的 _setargv 或 _westargv 而 不 加 载 它 们 的 库 版 本 。
类 似 地 , 如 果 你 不 通 过 envp 参 量 访 问 该 环 境 表 ,可 以 提 供 自 己 的 空 例 程 放在 环 境 处 理 例 程 _setenvp( 或 _wsetenvp) 中 。
如 果 你 的 程 序 调 用 C 运 行 库 中 的 _spawn 或 _exec 簇 的 例 程 ,你 不 要 阻 止该 环 境 处 理 例 程 , 因 为 这 个 例 程 用 于 从 繁 育 进 程 传 递 一 个 环 境 给 新 进程 。
生 存 期 、 范 围 、 可 见 性 和 连 接
为 了 理 解 C 程 序 如 何 工 作 的 , 你 必 须 掌 握 程 序 中 使 用 变 量 和 函 数 的 规则 。 几 个 概 念 对 于 掌 握 这 些 规 则 是 重 要 的 :
-
生 存 期
-
范 围 和 可 见 性
-
连 接
生 存 期
“ 生 存 期 ” 是 一 个 程 序 执 行 期 间 一 个 变 量 或 函 数 存 在 的 周 期 。 标 识 符 的存 储 期 间 确 定 了 它 的 生 存 期 。
用 存 储 类 指 示 符 static 说 明 的 标 识 具 有 静 态 存 储 期 。 静 态 存 储 期 ( 也 称 为“ 全 局 ” ) 的 标 识 符 在 一 个 程 序 期 间 具 有 存 储 和 确 定 的 值 。 在 程 序 启 动之 前 仅 一 次 初 始 化 就 确 定 了 存 储 和 值 。 以 外 部 或 内 部 连 接 说 明 的 标 识 符也 具 有 静 态 存 储 期 ( 参 见 本 章 后 面 的 “ 连 接 ” )。
不 以 static 存 储 类 指 示 符 说 明 的 标 识 符 如 果 在 一 个 函 数 内 部 说 明 ,它 具 有自 动 存 储 期 , 具 有 自 动 存 储 期 的 标 识 符 (一 个 局 部 的 标 识 符 ) 仅 在 说 明 或 定义 该 标 识 符 的 块 中 具 有 存 储 和 确 定 的 值 , 一 个 自 动 标 识 符 在 程 序 每 次 进入 该 块 时 分 配 新 的 存 储 , 当 程 序 退 出 该 块 时 会 丢 失 它 的 存 储 ( 和 它 的 值 )。在 一 个 函 数 中 以 非 连 接 说 明 的 标 识 符 也 具 有 自 动 存 储 期 。
如 下 规 则 指 出 一 个 标 识 符 是 否 具 有 全 局 ( 静 态 的 ) 或 局 部 的 ( 自 动 的 ) 生 存期 :
-
所 有 函 数 都 具 有 静 态 生 存 期 。 因 此 它 们 存 在 于 程 序 执 行 期 间 的 任 何时 候 。 在 外 部 层 说 明 的 标 识 符 ( 也 就 是 , 程 序 中 函 数 定 义 同 层 的 所 有块 的 外 部 ) 总 是 全 局 ( 静 态 ) 生 存 期 。
-
如 果 一 个 局 部 变 量 有 一 个 初 始 化 器 , 每 次 建 立 该 变 量 时 都 初 始 化 它( 除 非 它 说 明 成 static) 。 函 数 参 数 也 有 局 部 生 存 期 , 你 可 以 在 一 个块 中 通 过 在 说 明 中 包 括 static 存 储 类 指 示 符 来 为 一 个 标 识 符 指 定全 局 生 存 期 。 一 旦 说 明 成 static, 该 变 量 保 留 它 从 该 块 的 一 个 入 口
到 下 一 个 入 口 的 值 。
虽 然 具 有 全 局 生 存 期 的 标 识 符 在 源 程 序 的 整 个 执 行 中 都 存 在 ( 例 如 , 一 个外 部 说 明 的 变 量 或 用 static 关 键 字 说 明 的 局 部 变 量 ), 它 可 能 在 程 序 的 所有 部 分 都 是 不 可 见 的 。 有 关 可 见 性 的 信 息 参 见 “ 范 围 和 可 见 性 ”。 有 关存 储 类 指 示 符 非 终 结 符 的 讨 论 参 见 第 3 章“ 说 明 和 类 型 ”的 中“ 存 储 类 ”。如 果 需 要 分 配 存 储 器 ( 动 态 的 ), 通 过 使 用 特 定 库 例 程 如 malloc 来 实 现 。既 然 动 态 存 储 器 分 配 使 用 库 例 程 , 它 不 作 为 语 言 的 一 部 分 。 参 见“ M icrosoft Visual C++ 6.0 运 行 库 参 考 ” 中 的 malloc 函 数 。
范 围 和 可 见 性
一 个 标 识 符 的 “ 可 见 性 ” 确 定 了 可 以 引 用 的 程 序 部 分 即 它 的 “ 范 围 ”。一 个 标 识 符 仅 在 它 的 “ 范 围 ” 所 包 括 的 程 序 部 分 是 可 见 的 ( 也 就 是 可 以使 用 的 ),它 对 包 含 它 的 文 件 、 函 数 、 块 或 函 数 原 型 可 以 是 有 限 制 的 ( 以 便增 大 限 制 ) 。 一 个 标 识 符 的 范 围 是 可 以 使 用 它 的 名 称 的 程 序 部 分 。 有 时称 之 为 “ 词 法 范 围 ”。 有 四 种 类 型 的 范 围 :函 数 、 文 件 、 块 和 函 数 原 型 。除 标 号 外 所 有 标 识 符 都 通 过 其 说 明 所 在 层 来 确 定 它 的 范 围 。 如 下 每 一 种类 型 的 规 则 确 定 了 一 个 程 序 中 标 识 符 的 可 见 性 :
文 件 范 围
具 有 文 件 范 围 的 说 明 或 类 型 指 示 符 出 现 在 任 何 块 或 参 数 表 的 外 面 , 可 以在 说 明 之 后 转 换 单 元 的 任 何 位 置 访 问 。 具 有 文 件 范 围 的 标 识 符 名 称 通 常称 为 “ 全 局 的 ” 或 “ 外 部 的 ”。 一 个 全 局 标 识 符 的 范 围 开 始 于 它 的 定 义或 说 明 的 地 方 , 终 止 于 该 转 换 单 位 的 未 尾 。
函 数 范 围
一 个 标 号 是 唯 一 具 有 函 数 范 围 的 标 识 符 。 一 个 标 号 通 过 它 使 用 的 语 句 隐含 地 说 明 了 。 在 一 个 函 数 中 标 号 名 称 必 须 是 唯 一 的 ( 有 关 标 号 和 标 号 名称 的 更 多 信 息 , 参 见 第 5 章 “ 语 句 ” 中 的 “ goto 和 标 号 语 句 ” )。
块 范 围
具 有 块 范 围 的 标 识 符 的 说 明 或 类 型 指 示 符 出 现 在 一 个 块 内 或 一 个 函 数 定义 的 形 式 参 数 的 说 明 表 中 。 它 仅 在 它 说 明 和 定 义 的 地 方 到 包 含 其 定 义 或说 明 的 块 的 末 尾 的 范 围 内 是 可 见 的 。 它 的 范 围 限 制 为 该 块 和 该 块 嵌 套 调用 的 块 到 关 闭 该 关 联 块 的 花 括 号 。 这 样 的 标 识 符 有 时 称 为 “ 局 部 变 量 ”。
函 数 原 型 范 围
具 有 函 数 原 型 范 围 的 标 识 符 的 说 明 或 类 型 指 示 符 出 现 在 一 个 函 数 原 型 中的 参 数 说 明 表 中 ( 不 是 该 函 数 的 说 明 部 分 ) 。 它 的 范 围 在 该 函 数 说 明 的 末尾 。
在 其 它 源 文 件 中 的 变 量 可 见 性 的 适 当 说 明 在 第 3 章 “ 说 明 和 类 型 ” 中 的“ 存 储 类 ” 中 描 述 。 在 外 部 层 用 static 存 储 类 指 示 符 说 明 的 变 量 和 函 数仅 在 定 义 它 们 的 源 文 件 中 是 可 见 的 ,所 有 其 它 函 数 是 全 局 可 见 的 。
生 存 期 和 可 见 性 总 结
表 2.1 是 大 多 数 标 识 符 的 生 存 期 和 可 见 性 特 性 的 总 结 。 开 头 三 列 给 出 定义 生 存 期 和 可 见 性 的 属 性 , 具 有 开 头 三 列 属 性 的 标 识 符 的 生 存 期 和 可 见性 在 第 4 列 和 第 5 列 中 给 出 。 但 该 表 不 包 括 所 有 可 能 的 情 况 。 有 关 更 多信 息 参 见 第 3 章 “ 说 明 和 类 型 ” 中 的 “ 存 储 类 ”。
表 2.1 生 存 期 和 可 见 性 总 结
属性 : 结果 :
层 项 存 储 类 指 示 生存期 可 见 性
符
文件范围 |
变量定义 变量说明 |
static extern |
全局的 全局的 |
出 现 它 的 源 文 件 中 的 剩余部分 在 出 现 它 的 源 文 件 中 |
||
---|---|---|---|---|---|---|
函 数 原 型 |
或 |
定 |
static |
全局的 |
的剩余部分 单个源文件 |
|
块范围 |
义 函数原型变量说明 |
extern extern |
全局的 全局的 |
源文件的剩余部分 块 |
||
变量定义 变量定义 |
static auto 或 |
全局的 局部的 |
块 块 |
|||
register |
如 下 例 子 说 明 了 块 、 嵌 套 和 变 量 的 可 见 性 :
#include <stdio.h>
int i=1; /*i 定义在外部层 */
int main() /*main 定义在外部层 */
{
printf("%d\n",i);/* 打印 1( 外部层 i 的值 ) */
{ /* 开始第一个嵌套的块 */
int i=2,j=3; /* i 和 j 定义在内部层 */ printf("%d %d\n",i,j); /* 打印 2,3 */
{ /* 开始第二个嵌套的块 */ int i=0; /* i 重新定义 */
printf("%d %d\n",i,j); /* 打印 0,3 */
} /* 结束第二个嵌套的块 */ printf("%d\n",i); /* 打印 2( 恢复外面的定义 ) */
} /* 结束第一个嵌套的块 */ printf("%d\n",i); /* 打印 1( 恢复外层定义 ) */
return 0;
}
本 例 中 , 有 四 层 可 见 性 :外 部 层 和 三 个 块 层 。 在 屏 幕 上 打 印 的 值 在 每 行 的后 面 都 有 注 释 。
连 接
标 识 符 的 名 称 在 不 同 的 范 围 可 以 指 不 同 的 标 识 符 , 一 个 标 识 符 在 不 同 范围 内 说 明 或 者 在 同 一 范 围 内 说 明 多 次 可 以 通 过 称 为 “ 连 接 ” 的 过 程 使 之指 向 相 同 的 标 识 符 或 函 数 。连 接 确 定 其 中 标 识 符 可 以 引 用 的 程 序 部 分 ( 它的 “ 可 见 性 ” )。 有 三 种 类 型 的 连 接 :内 部 的 、 外 部 的 和 无 连 接 。
内 部 连 接
如 果 一 个 对 象 或 一 个 函 数 的 一 个 文 件 范 围 标 识 符 的 说 明 包 含 存 储 类 指 示符 static , 该 标 识 符 具 有 内 部 连 接 。 否 则 ,该 标 识 符 有 外 部 连 接 。 有 关 存储 类 标 识 符 非 终 结 符 的 讨 论 , 参 见 第 3 章 “ 说 明 和 类 型 ” 中 的“ 存 储 类 ”。在 一 个 转 换 单 元 中 , 具 有 内 部 连 接 的 标 识 符 的 每 个 实 例 表 示 同 样 的 标 识符 或 函 数 。 内 部 连 接 的 标 识 符 对 于 一 个 转 换 单 元 是 唯 一 的 。
外 部 连 接
如 果 在 文 件 范 围 层 的 标 识 符 的 第 一 次 说 明 没 有 使 用 static 存 储 类 指 示 符 ,
该 对 象 具 有 外 部 连 接 。
如 果 一 个 函 数 的 一 个 标 识 符 的 说 明 没 有 存 储 类 指 示 符 。 它 的 连 接 好 象 用存 储 类 指 示 符 extern 说 明 来 确 定 。 如 果 一 个 对 象 的 标 识 符 说 明 具 有 文 件范 围 且 没 有 存 储 类 指 示 符 , 则 它 的 连 接 是 外 部 的 。
- 个 具 有 外 部 连 接 的 标 识 符 的 名 称 与 其 它 任 何 相 同 名 称 的 外 部 连 接 的 说明 表 示 相 同 的 函 数 或 数 据 对 象 , 这 两 个 说 明 可 能 在 同 一 转 换 单 元 中 或 不同 的 转 换 单 元 中 。 如 果 该 对 象 或 函 数 还 具 有 全 局 生 存 期 , 那 么 该 对 象 或程 序 由 整 个 程 序 共 享 。
无 连 接 的
如 果 在 一 个 块 中 的 标 识 符 说 明 没 有 包 括 extern 存 储 类 指 示 符 ,该 标 识 符是 无 连 接 的 ,对 于 这 个 函 数 是 唯 一 的 。
如 下 标 识 符 是 无 连 接 的 :
-
一 个 标 识 符 说 明 成 非 对 象 或 函 数 的 其 它 任 何 事 情 。
-
一 个 标 识 符 说 明 成 一 个 函 数 参 数 。
-
一 个 对 象 的 块 范 围 标 识 符 不 以 extern 存 储 类 指 示 符 说 明 。
如 果 一 个 标 识 符 是 无 连 接 的 , 在 同 一 范 围 层 的 相 同 名 称 的 多 次 说 明 ( 在 一个 说 明 或 类 型 指 示 符 中 ) 会 产 生 一 个 符 号 重 新 定 义 错 误 。
名 称 空 间
编 译 器 建 立 “ 名 称 空 间 ” 用 于 识 别 用 于 各 种 不 同 项 的 标 识 符 。 在 每 个 名称 空 间 中 的 名 称 必 须 是 唯 一 的 以 避 免 冲 突 , 但 相 同 的 标 识 符 可 以 出 现 在多 个 名 称 空 间 中 。 这 意 味 着 你 可 以 为 两 个 或 多 个 不 同 的 项 使 用 相 同 的 标识 符 , 提 供 的 项 在 不 同 的 名 称 空 间 中 。 编 译 器 基 于 程 序 中 标 识 符 的 句 法上 下 文 来 解 决 引 用 。
注 意 : 不 要 将 有 限 制 的 C 的 名 称 空 间 表 示 与 C++ “ 名 称 空 间 ” 特 征 相混 淆 。 有 关 更 多 信 息 参 见 本 卷 后 面 “ M icrosoft Visual C++ 6.0 语 言 参 考 ” 中 的 第 6 章 “ 说 明 ” 的 “ 名 称 空 间 ”。
下 面 列 出 了 C 中 使 用 的 名 称 空 间 的 描 述 :
语 句 标 号
命 名 的 语 句 标 号 是 语 句 部 分 。 语 句 标 号 的 定 义 总 是 跟 着 一 个 冒 号 但 不 是一 个 case 标 号 部 分 。 语 句 标 号 的 使 用 总 是 跟 在 goto 关 键 词 的 后 面 。 语名 标 号 不 要 与 其 它 名 称 或 其 它 函 数 的 标 号 名 称 进 行 区 分 。
结 构 、 联 合 和 枚 举 标 志
这 些 标 志 是 结 构 、 联 合 和 枚 举 类 型 标 识 符 的 一 部 分 ,如 果 出 现 , 总 是 直 接跟 随 保 留 字 struct、 union 或 enum 。 该 标 志 名 称 必 须 与 其 它 相 同 可 见 性的 结 构 、 枚 举 或 联 合 标 志 相 区 别 。
结 构 或 联 合 的 成 员
在 名 称 空 间 中 分 配 与 每 个 结 构 和 联 合 类 型 相 关 联 的 成 员 名 称 , 也 就 是 , 相同 的 标 识 符 可 以 同 时 是 不 同 结 构 或 联 合 的 成 员 的 组 成 成 分 名 称 。 组 成 成分 的 定 义 总 是 出 现 在 结 构 或 联 合 类 型 指 示 符 中 。 组 成 成 分 名 称 的 使 用 总是 直 接 跟 随 成 员 选 择 运 算 符 (-> 和 .)。 在 结 构 或 联 合 中 ,一 个 成 员 名 称 必 须是 唯 一 的 , 但 为 了 与 其 它 名 称 区 别 , 要 包 含 不 同 结 构 和 联 合 的 成 员 的 名 称或 结 构 本 身 的 名 称 。
普 通 标 识 符
名 称 空 间 中 的 所 有 其 它 名 称 包 括 所 有 变 量 、 函 数 ( 包 括 形 式 参 数 和 局 部变 量 ) 和 枚 举 常 量 。 标 识 符 名 称 具 有 嵌 套 的 可 见 性 , 因 此 你 可 以 在 块 中 重新 定 义 它 们 。
typedef 标 识 符
类 型 定 义 (typedef) 名 称 不 能 在 同 一 范 围 内 用 作 标 识 符 。
例 如 , 因 为 结 构 标 志 、 结 构 成 员 和 变 量 名 称 在 三 种 不 同 的 名 称 空 间 中 , 本例 中 三 个 项 都 命 名 为 student 不 会 有 冲 突 。 每 个 项 的 上 下 文 允 许 正 确 地解 释 程 序 中 student 的 每 次 出 现 ( 有 关 结 构 的 信 息 ,参 见 第 3 章 “ 说 明 和 类型 ” 中 的 “ 结 构 说 明 ” ):
struct student {
char strdent [20]
int class; int id;
} student;
当 student 出 现 在 struct 关 键 字 之 后 时 , 编 译 器 识 别 它 为 结 构 标 志 。 当student 出 现 在 一 个 成 员 选 择 地 运 算 符 (-> 或 .) 之 后 时 , 该 名 称 指 的 是 结 构成 员 。 在 其 它 上 下 文 中 ,student 指 的 是 结 构 变 量 。 但 为 了 不 造 成 模 糊 , 建议 不 重 载 该 标 志 名 称 空 间 。