第3章、Linux下C编程基础



Similar documents
《C语言基础入门》课程教学大纲

<433A5C446F63756D656E E E67735C41646D696E F725CD7C0C3E65CC2DBCEC4CFB5CDB3CAB9D3C3D6B8C4CFA3A8BCF2BBAFA3A95CCAB9D3C3D6B8C4CF31302D31392E646F63>

I

修改版-操作手册.doc

说 明 为 了 反 映 教 运 行 的 基 本 状 态, 为 校 和 院 制 定 相 关 政 策 和 进 行 教 建 设 与 改 革 提 供 据 依 据, 校 从 程 资 源 ( 开 类 别 开 量 规 模 ) 教 师 结 构 程 考 核 等 维 度, 对 2015 年 春 季 期 教 运 行 基

Microsoft Word - 第7章 图表反转形态.doc

第2章 数据类型、常量与变量

何 秋 琳 张 立 春 视 觉 学 习 研 究 进 展 视 觉 注 意 视 觉 感 知

0 年 上 半 年 评 价 与 考 核 细 则 序 号 部 门 要 素 值 考 核 内 容 考 核 方 式 考 核 标 准 考 核 ( 扣 原 因 ) 考 评 得 3 安 全 生 产 目 30 无 同 等 责 任 以 上 道 路 交 通 亡 人 事 故 无 轻 伤 责 任 事 故 无 重 大 质 量

HSK( 一 级 ) 考 查 考 生 的 日 常 汉 语 应 用 能 力, 它 对 应 于 国 际 汉 语 能 力 标 准 一 级 欧 洲 语 言 共 同 参 考 框 架 (CEF) A1 级 通 过 HSK( 一 级 ) 的 考 生 可 以 理 解 并 使 用 一 些 非 常 简 单 的 汉 语


目 录 关 于 图 标... 3 登 陆 主 界 面... 3 工 单 管 理... 5 工 单 列 表... 5 搜 索 工 单... 5 工 单 详 情... 6 创 建 工 单... 9 设 备 管 理 巡 检 计 划 查 询 详 情 销 售 管


2 熟 悉 Visual Basic 的 集 成 开 发 环 境 3 了 解 可 视 化 面 向 对 象 编 程 事 件 驱 动 交 互 式 开 发 等 基 本 概 念 4 了 解 Visual Basic 的 特 点 环 境 要 求 与 安 装 方 法 1 Visual Basic 开 发 应 用

,,,,, :,, (.,, );, (, : ), (.., ;. &., ;.. &.., ;, ;, ),,,,,,, ( ) ( ),,,,.,,,,,, : ;, ;,.,,,,, (., : - ),,,, ( ),,,, (, : ),, :,

国债回购交易业务指引

登录、注册功能的测试用例设计.doc

一 公 共 卫 生 硕 士 专 业 学 位 论 文 的 概 述 学 位 论 文 是 对 研 究 生 进 行 科 学 研 究 或 承 担 专 门 技 术 工 作 的 全 面 训 练, 是 培 养 研 究 生 创 新 能 力, 综 合 运 用 所 学 知 识 发 现 问 题, 分 析 问 题 和 解 决

评 委 : 李 炎 斌 - 个 人 技 术 标 资 信 标 初 步 审 查 明 细 表 序 号 投 标 单 位 投 标 函 未 按 招 标 文 件 规 定 填 写 漏 填 或 内 容 填 写 错 误 的 ; 不 同 投 标 人 的 投 标 文 件 由 同 一 台 电 脑 或 同 一 家 投 标 单

龚 亚 夫 在 重 新 思 考 基 础 教 育 英 语 教 学 的 理 念 一 文 中 援 引 的 观 点 认 为 当 跳 出 本 族 语 主 义 的 思 维 定 式 后 需 要 重 新 思 考 许 多 相 连 带 的 问 题 比 如 许 多 发 音 的 细 微 区 别 并 不 影 响 理 解 和

18 上 报 该 学 期 新 生 数 据 至 阳 光 平 台 第 一 学 期 第 四 周 至 第 六 周 19 督 促 学 习 中 心 提 交 新 增 专 业 申 请 第 一 学 期 第 四 周 至 第 八 周 20 编 制 全 国 网 络 统 考 十 二 月 批 次 考 前 模 拟 题 第 一 学

Microsoft Word - 第3章.doc


4 进 入 交 互 区 设 置 的 组 件 管 理, 在 组 件 管 理 中, 教 师 可 以 选 择 课 程 空 间 中 的 所 有 组 件, 并 通 过 点 击 启 用 或 不 启 用 选 定 组 件 在 课 程 空 间 中 的 显 示 5 进 入 工 作 室 管 理 的 工 作 室 首 页,

<4D F736F F D D323630D6D0B9FAD3A6B6D4C6F8BAF2B1E4BBAFB5C4D5FEB2DFD3EBD0D0B6AF C4EAB6C8B1A8B8E6>

Microsoft Word - 文件汇编.doc

全国建筑市场注册执业人员不良行为记录认定标准(试行).doc

2006年顺德区高中阶段学校招生录取分数线

自 服 务 按 钮 无 法 访 问 新 系 统 的 自 服 务 页 面 因 此 建 议 用 户 从 信 网 中 心 ( 主 页, 右 下 角 位 置 的 常 用 下 载, 或 校 园 网 用 户 自 服 务 ( 首 页

深圳市新亚电子制程股份有限公司

评 委 : 徐 岩 宇 - 个 人 技 术 标 资 信 标 初 步 审 查 明 细 表 序 号 投 标 单 位 投 标 函 未 按 招 标 文 件 规 定 填 写 漏 填 或 内 容 填 写 错 误 的 ; 不 同 投 标 人 的 投 标 文 件 由 同 一 台 电 脑 或 同 一 家 投 标 单

金 不 少 于 800 万 元, 净 资 产 不 少 于 960 万 元 ; (3) 近 五 年 独 立 承 担 过 单 项 合 同 额 不 少 于 1000 万 元 的 智 能 化 工 程 ( 设 计 或 施 工 或 设 计 施 工 一 体 ) 不 少 于 2 项 ; (4) 近 三 年 每 年

 编号:

导 数 和 微 分 的 概 念 导 数 的 几 何 意 义 和 物 理 意 义 函 数 的 可 导 性 与 连 续 性 之 间 的 关 系 平 面 曲 线 的 切 线 和 法 线 导 数 和 微 分 的 四 则 运 算 基 本 初 等 函 数 的 导 数 复 合 函 数 反 函 数 隐 函 数 以

云信Linux SSH认证代理用户手册

目 录 一 系 统 访 问... 1 二 门 户 首 页 申 报 用 户 审 核 用 户... 2 三 系 统 登 录 用 户 名 密 码 登 录 新 用 户 注 册 用 户 登 录 已 注 册 用

( 二 ) 现 行 统 一 高 考 制 度 不 利 于 培 养 人 的 创 新 精 神,,,,,,,,,,,,, [ ],,,,,,,,,,, :, ;,,,,,,? ( 三 ) 现 行 统 一 高 考 制 度 不 利 于 全 体 学 生 都 获 得 全 面 发 展,, [ ],,,,,,,,,,,

定 位 和 描 述 : 程 序 设 计 / 办 公 软 件 高 级 应 用 级 考 核 内 容 包 括 计 算 机 语 言 与 基 础 程 序 设 计 能 力, 要 求 参 试 者 掌 握 一 门 计 算 机 语 言, 可 选 类 别 有 高 级 语 言 程 序 设 计 类 数 据 库 编 程 类

世华财讯模拟操作手册

Template BR_Rec_2005.dot

第二讲 数列

类 似 地, 又 可 定 义 变 下 限 的 定 积 分 : ( ). 与 ψ 统 称 为 变 限 积 分. f ( ) d f ( t) dt,, 注 在 变 限 积 分 (1) 与 () 中, 不 可 再 把 积 分 变 量 写 成 的 形 式 ( 例 如 ) 以 免 与 积 分 上 下 限 的

采 取 行 动 的 机 会 90% 开 拓 成 功 的 道 路 2

马 克 思 主 义 公 正 观 的 基 本 向 度 及 方 法 论 原 则!! # #

上海证券交易所会议纪要

i 1) 系 统 运 作 前 设 定 *1. [2.1 网 页 主 机 名 称 设 定 ] -- 设 定 校 务 系 统 的 主 机 IP 地 址, 以 供 其 他 个 人 电 脑 连 接 及 使 用 该 系 统 *2. [2.3.1 输 入 / 修 改 学 校 资 料 ] -- 输 入 系 统 使

黄 金 原 油 总 持 仓 增 长, 同 比 增 幅 分 别 为 4.2% 和 4.1% 而 铜 白 银 以 及 玉 米 则 出 现 减 持, 减 持 同 比 减 少 分 别 为 9.4%,9.4% 以 及 6.5% 大 豆, 豆 粕 结 束 连 续 4 周 总 持 仓 量 增 长, 出 现 小 幅

( ) 信 号 与 系 统 Ⅰ 学 科 基 础 必 修 课 教 周 2016 年 06 月 13 日 (08:00-09:35) ( )

附 件 : 上 海 市 建 筑 施 工 企 业 施 工 现 场 项 目 管 理 机 构 关 键 岗 位 人 员 配 备 指 南 二 一 四 年 九 月 十 一 日 2

三门峡市质量技术监督局清单公示

<433A5C C6B73625C B746F705CB9FABCCAD6D0D2BDD2A9D7A8D2B5B8DFBCB6BCBCCAF5D6B0B3C6C6C0C9F3C9EAC7EBD6B8C4CFA3A CDA8D3C3B0E6A3A92E646F63>

第 一 部 分 MagiCAD for Revit 安 装 流 程

<4D F736F F D20B9D8D3DAB0BABBAAA3A8C9CFBAA3A3A9D7D4B6AFBBAFB9A4B3CCB9C9B7DDD3D0CFDEB9ABCBBE C4EAC4EAB6C8B9C9B6ABB4F3BBE1B7A8C2C9D2E2BCFBCAE92E646F6378>

<4D F736F F D C4EAB9A4B3CCCBB6CABFCAFDD1A7D7A8D2B5BFCEBFBCCAD4B4F3B8D9D3EBD2AAC7F3>

抗 战 时 期 国 民 政 府 的 银 行 监 理 体 制 探 析 % # % % % ) % % # # + #, ) +, % % % % % % % %

目 录 第 一 章 博 星 卓 越 电 子 商 务 营 销 策 划 实 践 平 台 硬 件 使 用 介 绍... 3 第 二 章 博 星 卓 越 电 子 商 务 营 销 策 划 实 践 平 台 管 理 员 端 功 能 使 用 介 绍 系 统 管 理 员 登 陆 班

第二部分 阅读理解(Part II Reabing Comprehension)

生产支援功能 使用说明书(IP-110 篇)

教师上报成绩流程图

3 复 试 如 何 准 备 4 复 试 成 绩 计 算 5 复 试 比 例 6 复 试 类 型 7 怎 么 样 面 对 各 种 复 试 04 05

(Microsoft Word - NCRE\314\345\317\265\265\367\325\37313\324\27221\272\3051.doc)

ETF、分级基金规模、份额变化统计

一、资质申请

一 开 放 性 的 政 策 与 法 规 二 两 岸 共 同 的 文 化 传 承 三 两 岸 高 校 各 自 具 有 专 业 优 势 远 见 杂 志 年 月 日

微软用户

Microsoft Word - 资料分析练习题09.doc

全国教师资格认定管理信息系统

<443A5C6D B5C30312EB9A4D7F7CEC4B5B55C30322EBACFCDACCEC4B5B55C C30342EC8CBC9E7CCFC5C31332ECFEEC4BFC5E0D1B55C E30385C322EB2D9D7F7CAD6B2E12E646F63>

课程类 别

untitled

全国艺术科学规划项目

正 规 培 训 达 规 定 标 准 学 时 数, 并 取 得 结 业 证 书 二 级 可 编 程 师 ( 具 备 以 下 条 件 之 一 者 ) (1) 连 续 从 事 本 职 业 工 作 13 年 以 上 (2) 取 得 本 职 业 三 级 职 业 资 格 证 书 后, 连 续 从 事 本 职 业

电信系教学大纲的基本规范

用节点法和网孔法进行电路分析

<4D F736F F D C3E6CFF2B6D4CFF3A3A8B5DAC8FDD5C220C0E0CCD8D0D4A3A92E646F63>

四川省农村义务教育学生

名 称 生 命 科 学 学 院 环 境 科 学 1 生 物 学 仅 接 收 院 内 调 剂, 初 试 分 数 满 足 我 院 生 物 学 复 试 最 低 分 数 线 生 命 科 学 学 院 生 态 学 5 生 态 学 或 生 物 学 生 命 科 学 学 院

工 程 造 价 咨 询 企 业 管 理 系 统 操 作 手 册 目 录 1 造 价 企 业 登 录 企 业 基 本 信 息 查 看 企 业 人 员 信 息 查 看 企 业 基 本 信 息 操 作 企 业 简 介 企 业 章

随着执业中医师资格考试制度的不断完善,本着为我校中医学专业认证服务的目的,本文通过对我校中医类毕业生参加2012年和2013年的中医执业医师考试成绩及通过率、掌握率进行分析,并与全国的平均水平进行差异比较分析,以此了解我校执业中医师考试的现状,进而反映我校中医类课程总体教学水平,发现考核知识模块教学中存在的不足,反馈给相关学院和教学管理部门,以此提高教学和管理水平。

目 录 一 激 活 账 号... 2 二 忘 记 密 码 后 如 何 找 回 密 码?... 3 三 如 何 管 理 学 校 信 息 及 球 队 学 生 教 师 等 信 息... 6 四 如 何 发 布 本 校 校 园 文 化? 五 如 何 向 教 师 发 送 通 知? 六

工 程 勘 察 资 质 标 准 根 据 建 设 工 程 勘 察 设 计 管 理 条 例 和 建 设 工 程 勘 察 设 计 资 质 管 理 规 定, 制 定 本 标 准 一 总 则 ( 一 ) 本 标 准 包 括 工 程 勘 察 相 应 专 业 类 型 主 要 专 业 技 术 人 员 配 备 技 术

珠江钢琴股东大会


际 联 考 的 非 美 术 类 本 科, 提 前 批 本 科 体 育 类 第 一 批 第 二 批 第 三 批 的 理 工 类 和 文 史 类 本 科 平 行 志 愿, 考 生 可 以 填 报 6 所 院 校 志 愿 符 合 贫 困 地 区 专 项 计 划 和 农 村 考 生 专 项 计 划 报 考

Cybozu Garoon 3 管理员手册

伊 犁 师 范 学 院 611 语 言 学 概 论 全 套 考 研 资 料 <2016 年 最 新 考 研 资 料 > 2-2 语 言 学 纲 要 笔 记, 由 考 取 本 校 本 专 业 高 分 研 究 生 总 结 而 来, 重 点 突 出, 借 助 此 笔 记 可 以 大 大 提 高 复 习 效

Excel basics

<4D F736F F D20BFC9B1E0B3CCD0F2BFD8D6C6CFB5CDB3C9E8BCC6CAA6B9FABCD2D6B0D2B5B1EAD7BC2E646F63>

目 录 页 1. 欢 迎 使 用 网 上 预 约 面 谈 访 问 系 统 新 用 户 新 用 户 登 入 帐 户 程 序 启 动 网 上 预 约 面 谈 访 问 帐 户 核 对 帐 户 的 地 址 资 料

一 从 分 封 制 到 郡 县 制 一 从 打 虎 亭 汉 墓 说 起

合 并 计 算 配 售 对 象 持 有 多 个 证 券 账 户 的, 多 个 证 券 账 户 市 值 合 并 计 算 确 认 多 个 证 券 账 户 为 同 一 配 售 对 象 持 有 的 原 则 为 证 券 账 户 注 册 资 料 中 的 账 户 持 有 人 名 称 有 效 身 份 证 明 文 件

第 六 章 债 券 股 票 价 值 评 估 1 考 点 一 : 债 券 价 值 的 影 响 因 素 2

火车浏览器脚本制作教程

3 月 30 日 在 中 国 证 券 报 上 海 证 券 报 证 券 时 报 证 券 日 报 和 上 海 证 券 交 易 所 网 站 上 发 出 召 开 本 次 股 东 大 会 公 告, 该 公 告 中 载 明 了 召 开 股 东 大 会 的 日 期 网 络 投 票 的 方 式 时 间 以 及 审


4.3.3 while 语 句 用 于 无 限 循 环 当 while 语 句 的 表 达 式 永 远 不 会 为 布 尔 假 时, 循 环 将 永 远 不 会 结 束, 形 成 无 限 循 环, 也 称 死 循 环 使 用 while 语 句 构 成 无 限 循 环 的 格 式 通 常

证监会行政审批事项目录


第3章 创建数据库

超 级 玛 丽 JAVA 小 游 戏 测 试 报 告 1. 导 言 1.1 编 写 目 的 该 文 档 的 目 的 是 描 述 超 级 玛 丽 JAVA 小 游 戏 的 系 统 测 试 的 总 结 报 告, 其 主 要 内 容 包 括 : 系 统 环 境 的 介 绍 功 能 的 实 现 的 测 试

Transcription:

第 3 章 Linux 下 C 编 程 基 础 本 章 目 标 本 章 将 带 领 读 者 学 习 在 Linux 中 进 行 C 语 言 编 程 的 基 本 技 能 学 习 了 本 章 后, 读 者 能 够 掌 握 如 下 内 容 熟 悉 Linux 系 统 下 的 开 发 环 境 熟 悉 vi 的 基 本 操 作 熟 练 emacs 的 基 本 操 作 熟 悉 gcc 编 译 器 的 基 本 原 理 熟 练 使 用 gcc 编 译 器 的 常 用 选 项 熟 练 使 用 gdb 的 调 试 技 术 熟 悉 makefile 基 本 原 理 及 语 法 规 范 熟 练 使 用 autoconf 和 automake 生 成 makefile

3.1 Linux 下 C 语 言 编 程 概 述 3.1.1 C 语 言 简 单 回 顾 C 语 言 最 早 是 由 贝 尔 实 验 室 的 Dennis Ritchie 为 了 UNIX 的 辅 助 开 发 而 编 写 的, 它 是 在 B 语 言 的 基 础 上 开 发 出 来 的 尽 管 C 语 言 不 是 专 门 针 对 UNIX 操 作 系 统 或 机 器 编 写 的, 但 它 与 UNIX 系 统 的 关 系 十 分 紧 密 由 于 它 的 硬 件 无 关 性 和 可 移 植 性, 使 C 语 言 逐 渐 成 为 世 界 上 使 用 最 广 泛 的 计 算 机 语 言 为 了 进 一 步 规 范 C 语 言 的 硬 件 无 关 性,1987 年, 美 国 国 家 标 准 协 会 (ANSI) 根 据 C 语 言 问 世 以 来 各 种 版 本 对 C 语 言 的 发 展 和 扩 充, 制 定 了 新 的 标 准, 称 为 ANSI C ANSI C 语 言 比 原 来 的 标 准 C 语 言 有 了 很 大 的 发 展 目 前 流 行 的 C 语 言 编 译 系 统 都 是 以 它 为 基 础 的 C 语 言 的 成 功 并 不 是 偶 然 的, 它 强 大 的 功 能 和 它 的 可 移 植 性 让 它 能 在 各 种 硬 件 平 台 上 游 刃 自 如 总 体 而 言,C 语 言 有 如 下 特 点 (1)C 语 言 是 中 级 语 言 它 把 高 级 语 言 的 基 本 结 构 和 语 句 与 低 级 语 言 的 实 用 性 结 合 起 来 C 语 言 可 以 像 汇 编 语 言 一 样 对 位 字 节 和 地 址 进 行 操 作, 而 这 三 者 是 计 算 机 最 基 本 的 工 作 单 元 (2)C 语 言 是 结 构 化 的 语 言 C 语 言 采 用 代 码 及 数 据 分 隔, 使 程 序 的 各 个 部 分 除 了 必 要 的 信 息 交 流 外 彼 此 独 立 这 种 结 构 化 方 式 可 使 程 序 层 次 清 晰, 便 于 使 用 维 护 以 及 调 试 C 语 言 是 以 函 数 形 式 提 供 给 用 户 的, 这 些 函 数 可 方 便 地 调 用, 并 具 有 多 种 循 环 条 件 语 句 控 制 程 序 流 向, 从 而 使 程 序 完 全 结 构 化 (3)C 语 言 功 能 齐 全 C 语 言 具 有 各 种 各 样 的 数 据 类 型, 并 引 入 了 指 针 的 概 念, 可 使 程 序 效 率 更 高 另 外,C 语 言 也 具 有 强 大 的 图 形 功 能, 支 持 多 种 显 示 器 和 驱 动 器, 而 且 计 算 功 能 逻 辑 判 断 功 能 也 比 较 强 大, 可 以 实 现 决 策 目 的 (4)C 语 言 可 移 植 性 强 C 语 言 适 合 多 种 操 作 系 统, 如 DOS Windows Linux, 也 适 合 多 种 体 系 结 构, 因 此 尤 其 适 合 在 嵌 入 式 领 域 的 开 发 3.1.2 Linux 下 C 语 言 编 程 环 境 概 述 Linux 下 的 C 语 言 程 序 设 计 与 在 其 他 环 境 中 的 C 程 序 设 计 一 样, 主 要 涉 及 编 辑 器 编 译 链 接 器 调 试 器 及 项 目 管 理 工 具 现 在 我 们 先 对 这 4 种 工 具 进 行 简 单 介 绍, 后 面 会 对 其 一 一 进 行 讲 解 (1) 编 辑 器. Linux 下 的 编 辑 器 就 如 Windows 下 的 记 事 本 写 字 板 等 一 样, 完 成 对 所 录 入 文 字 的 编 辑 功 能 Linux 中 最 常 用 的 编 辑 器 有 vi(vim) 和 emacs, emacs 它 们 功 能 强 大 使 用 方 便, 深 受 编 程 爱 好 者 的 喜 爱 在 本 书 中, 着 重 介 绍 vi 和 (2) 编 译 链 接 器 编 译 是 指 源 代 码 转 化 生 成 可 执 行 代 码 的 过 程, 它 所 完 成 的 主 要 工 作 如 图 3.1 所 示

图 3.1 编 译 过 程 可 见, 编 译 过 程 是 非 常 复 杂 的, 它 包 括 词 法 语 法 和 语 义 的 分 析 中 间 代 码 的 生 成 和 优 化 符 号 表 的 管 理 和 出 错 处 理 等 在 Linux 中, 最 常 用 的 编 译 器 是 gcc 编 译 器 它 是 GNU 推 出 的 功 能 强 大 性 能 优 越 的 多 平 台 编 译 器, 其 执 行 效 率 与 一 般 的 编 译 器 相 比 平 均 效 率 要 高 20%~30% (3) 调 试 器 调 试 器 并 不 是 代 码 执 行 的 必 备 工 具, 而 是 专 为 方 便 程 序 员 调 试 程 序 而 用 的 有 编 程 经 验 的 读 者 都 知 道, 在 编 程 的 过 程 当 中, 往 往 调 试 所 消 耗 的 时 间 远 远 大 于 编 写 代 码 的 时 间 因 此, 有 一 个 功 能 强 大 使 用 方 便 的 调 试 器 是 必 不 可 少 的 gdb 是 绝 大 多 数 Linux 开 发 人 员 所 使 用 的 调 试 器, 它 可 以 方 便 地 设 置 断 点 单 步 跟 踪 等, 足 以 满 足 开 发 人 员 的 需 要 (4) 项 目 管 理 器 Linux 中 的 项 目 管 理 器 make 有 些 类 似 于 Windows 中 Visual c++ 里 的 工 程, 它 是 一 种 控 制 编 译 或 者 重 复 编 译 软 件 的 工 具, 另 外, 它 还 能 自 动 管 理 软 件 编 译 的 内 容 方 式 和 时 机, 使 程 序 员 能 够 把 精 力 集 中 在 代 码 的 编 写 上 而 不 是 在 源 代 码 的 组 织 上 3.2 常 用 编 辑 器 3.2.1 进 入 vi Linux 系 统 提 供 了 一 个 完 整 的 编 辑 器 家 族 系 列, 如 Ed Ex vi 和 emacs 等 按 功 能 它 们 可 以 分 为 两 大 类 : 行 编 辑 器 (Ed Ex) 和 全 屏 幕 编 辑 器 (vi emacs) 行 编 辑 器 每 次 只 能 对 一 行 进 行 操 作, 使 用 起 来 很 不 方 便 而 全 屏 幕 编 辑 器 可 以 对 整 个 屏 幕 进

行 编 辑, 用 户 编 辑 的 文 件 直 接 显 示 在 屏 幕 上, 从 而 克 服 了 行 编 辑 那 种 不 直 观 的 操 作 方 式, 便 于 用 户 学 习 和 使 用, 具 有 强 大 的 功 能 vi 是 Linux 系 统 的 第 一 个 全 屏 幕 交 互 式 编 辑 程 序, 它 从 诞 生 至 今 一 直 得 到 广 大 用 户 的 青 睐, 历 经 数 十 年 仍 然 是 人 们 主 要 使 用 的 文 本 编 辑 工 具, 足 以 见 其 生 命 力 之 强, 而 强 大 的 生 命 力 是 其 强 大 的 功 能 带 来 的 由 于 大 多 数 读 者 在 此 之 前 都 已 经 用 惯 了 Windows 平 台 上 的 编 辑 器, 因 此, 在 刚 刚 接 触 时 总 会 或 多 或 少 不 适 应, 但 只 要 习 惯 之 后, 就 能 感 受 到 它 的 方 便 与 快 捷 1.vi 的 模 式 vi 有 3 种 模 式, 分 别 为 命 令 行 模 式 插 入 模 式 及 命 令 行 模 式 下 面 具 体 介 绍 各 模 式 的 功 能 (1) 命 令 行 模 式 用 户 在 用 vi 编 辑 文 件 时, 最 初 进 入 的 为 一 般 模 式 在 该 模 式 中 用 户 可 以 通 过 上 下 移 动 光 标 进 行 删 除 字 符 或 整 行 删 除 等 操 作, 也 可 以 进 行 复 制 粘 贴 等 操 作, 但 无 法 编 辑 文 字 (2) 插 入 模 式 只 有 在 该 模 式 下, 用 户 才 能 进 行 文 字 编 辑 输 入, 用 户 按 [ESC] 可 键 回 到 命 令 行 模 式 (3) 底 行 模 式 在 该 模 式 下, 光 标 位 于 屏 幕 的 底 行 用 户 可 以 进 行 文 件 保 存 或 退 出 操 作, 也 可 以 设 置 编 辑 环 境, 如 寻 找 字 符 串 列 出 行 号 等 2.vi 的 基 本 流 程 (1) 进 入 vi, 即 在 命 令 行 下 键 入 vi hello ( 文 件 名 ) 此 时 进 入 的 是 命 令 行 模 式, 光 标 位 于 屏 幕 的 上 方, 如 图 3.2 所 示 图 3.2 进 入 vi 命 令 行 模 式

(2) 在 命 令 行 模 式 下 键 入 i 进 入 插 入 模 式, 如 图 3.3 所 示 可 以 看 出, 在 屏 幕 底 部 显 示 有 插 入 表 示 插 入 模 式 中 的 输 入 状 态, 在 该 模 式 下 可 以 输 入 文 字 信 息 图 3.3 进 入 vi 插 入 模 式 (3) 最 后, 在 插 入 模 式 中, 按 Esc 键, 则 当 前 模 式 转 入 命 令 行 模 式, 并 在 底 行 行 中 输 入 :wq ( 存 盘 退 出 ) 进 入 底 行 模 式, 如 图 3.4 所 示 这 样, 就 完 成 了 一 个 简 单 的 vi 操 作 流 程 : 命 令 行 模 式 插 入 模 式 底 行 模 式 由 于 vi 在 不 同 的 模 式 下 有 不 同 的 操 作 功 能, 因 此, 读 者 一 定 要 时 刻 注 意 屏 幕 最 下 方 的 提 示, 分 清 所 在 的 模 式

图 3.4 进 入 vi 底 行 模 式 3.vi 的 各 模 式 功 能 键 (1) 命 令 行 模 式 常 见 功 能 键 如 表 3.1 所 示 表 3.1 vi 命 令 行 模 式 功 能 键 功 能 键 功 能 i a o [ctrl]+[b] [ctrl]+[f] [ctrl]+[u] [ctrl]+[d] 切 换 到 插 入 模 式, 在 目 前 的 光 标 所 在 处 插 入 输 入 的 文 字, 已 存 在 的 文 字 会 向 后 退 切 换 到 插 入 模 式, 并 从 目 前 光 标 所 在 位 置 的 下 一 个 位 置 开 始 输 入 文 字 切 换 到 插 入 模 式, 且 从 行 首 开 始 插 入 新 的 一 行 屏 幕 往 后 翻 动 一 页 屏 幕 往 前 翻 动 一 页 屏 幕 往 后 翻 动 半 页 屏 幕 往 前 翻 动 半 页 0( 数 字 0) 光 标 移 到 本 行 的 开 头 G ng 光 标 移 动 到 文 件 的 最 后 光 标 移 动 到 第 n 行 $ 移 动 到 光 标 所 在 行 的 行 尾 n<enter> /name?name x X dd ndd yy nyy 光 标 向 下 移 动 n 行 在 光 标 之 后 查 找 一 个 名 为 name 的 字 符 串 在 光 标 之 前 查 找 一 个 名 为 name 的 字 符 串 删 除 光 标 所 在 位 置 的 一 个 字 符 删 除 光 标 所 在 位 置 的 前 一 个 字 符 删 除 光 标 所 在 行 从 光 标 所 在 行 开 始 向 下 删 除 n 行 复 制 光 标 所 在 行 复 制 光 标 所 在 行 开 始 的 向 下 n 行 p 将 缓 冲 区 内 的 字 符 粘 贴 到 光 标 所 在 位 置 ( 与 yy 搭 配 ) u 恢 复 前 一 个 动 作 (2) 插 入 模 式 的 功 能 键 只 有 一 个, 即 按 Esc 键 可 回 到 命 令 行 模 式 (3) 底 行 模 式 常 见 功 能 键 如 表 3.2 所 示 表 3.2 vi 底 行 模 式 功 能 键 功 能 键 功 能 :w 将 编 辑 的 文 件 保 存 到 磁 盘 中

:q 退 出 vi( 系 统 对 做 过 修 改 的 文 件 会 给 出 提 示 ) :q! 强 制 退 出 vi( 对 修 改 过 的 文 件 不 作 保 存 ) :wq 存 盘 后 退 出 :w [filename] 另 存 一 个 名 为 filename 的 文 件 :set nu :set nonu 显 示 行 号, 设 定 之 后, 会 在 每 一 行 的 前 面 显 示 对 应 行 号 取 消 行 号 显 示 注 意 vim 是 vi 的 升 级 版, 与 vi 相 比 扩 展 了 很 多 功 能 且 保 持 与 vi 的 90% 相 兼 容, 感 兴 趣 的 读 者 可 以 查 看 相 关 资 料 进 行 学 习 3.2.2 初 探 emacs 正 如 前 面 所 述,vi 是 一 款 功 能 非 常 强 大 的 编 辑 器, 它 能 够 方 便 快 捷 高 效 地 完 成 用 户 的 任 务, 那 么, 在 此 再 次 向 读 者 介 绍 另 一 款 编 辑 器 是 否 多 此 一 举 呢? 答 案 是 否 定 的 因 为 emacs 不 仅 仅 是 一 款 功 能 强 大 的 编 译 器, 而 且 是 一 款 融 合 编 辑 编 译 调 试 于 一 体 的 开 发 环 境 虽 然, 它 没 有 Visual Studio 一 样 绚 丽 的 界 面, 但 是 它 可 以 在 没 有 图 形 显 示 的 终 端 环 境 下 出 色 的 工 作, 相 信 追 求 强 大 功 能 和 工 作 效 率 的 用 户 不 会 介 意 它 朴 素 的 界 面 的 emacs 的 使 用 和 vi 截 然 不 同 在 emacs 里, 没 有 类 似 于 vi 的 3 种 模 式 emacs 只 有 一 种 模 式, 也 就 是 编 辑 模 式, 而 且 它 的 命 令 全 靠 功 能 键 完 成 因 此, 功 能 键 也 就 相 当 重 要 了 但 emacs 却 还 使 用 一 个 不 同 vi 的 模 式, 它 的 模 式 是 指 各 种 辅 助 环 境 比 如, 当 编 辑 普 通 文 本 时, 使 用 的 是 文 本 模 式 (Text Mode), 而 当 写 程 序 时, 使 用 的 则 是 如 c 模 式 shell 模 式 等 境 下 面, 首 先 介 绍 一 下 emacs 作 为 编 辑 器 的 使 用 方 法, 以 帮 助 读 者 熟 悉 emacs 的 环 注 意 emacs 缩 写 注 释 : C+<chr> 表 示 按 住 Ctrl 键 的 同 时 键 入 字 符 <chr> 因 此,C+f 就 表 示 按 住 Ctrl 键 同 时 键 入 f M+<chr> 表 示 当 键 入 字 符 <chr> 时 同 时 按 住 Meta 或 Edit 或 Alt 键 ( 通 常 为 Alt 键 ) 1.emacs 安 装 现 在 较 新 版 本 的 Linux( 如 本 书 中 所 用 的 Red Hat Enterprise 4 AS) 的 安 装 光 盘 中 一 般 都 自 带 有 emacs 的 安 装 包, 用 户 可 以 通 过 安 装 光 盘 进 行 安 装 ( 一 般 在 第 2 张 光 盘 中 ) 2. 启 动 emacs 安 装 完 emacs 之 后, 只 需 在 命 令 行 键 入 emacs [ 文 件 名 ] ( 若 缺 省 文 件 名, 也 可 在 emacs 编 辑 文 件 后 另 存 时 指 定 ), 也 可 从 编 程 emacs 打 开, 如 3.5 图 所 示 的 就 是 从 编 程 emacs 打 开 的 emacs 欢 迎 界 面

图 3.5 emacs 欢 迎 界 面 接 着 可 单 击 任 意 键 进 入 emacs 的 工 作 窗 口, 如 图 3.6 所 示 从 图 中 可 见,emacs 的 工 作 窗 口 分 为 上 下 两 个 部 分, 上 部 为 编 辑 窗 口, 底 部 为 命 令 显 示 窗 口, 用 户 执 行 功 能 键 的 功 能 都 会 在 底 部 有 相 应 的 显 示, 有 时 也 需 要 用 户 在 底 部 窗 口 输 入 相 应 的 命 令, 如 查 找 字 符 串 等 图 3.6 emacs 的 工 作 窗 口

3. 进 入 emacs 在 进 入 emacs 后, 即 可 进 行 文 件 的 编 辑 由 于 emacs 只 有 一 种 编 辑 模 式, 因 此 用 户 无 需 进 行 模 式 间 的 切 换 下 面 介 绍 emacs 中 基 本 编 辑 功 能 键 (1) 移 动 光 标 虽 然 在 emacs 中 可 以 使 用 上 下 左 右 方 向 键 来 移 动 单 个 字 符, 但 笔 者 还 是 建 议 读 者 学 习 其 对 应 功 能 键, 因 为 它 们 不 仅 能 在 所 有 类 型 的 终 端 上 工 作, 而 且 读 者 将 会 发 现 在 熟 练 使 用 之 后, 输 入 这 些 Ctrl 加 字 符 会 比 按 方 向 键 快 很 多 表 3.3 列 举 了 emacs 中 光 标 移 动 的 常 见 功 能 键 表 3.3 emacs 光 标 移 动 功 能 键 功 能 键 功 能 功 能 键 功 能 C-f 向 前 移 动 一 个 字 符 M-b 向 后 移 动 一 个 单 词 C-b 向 后 移 动 一 个 字 符 C-a 移 动 到 行 首 C-p 移 动 到 上 一 行 C-e 移 动 到 行 尾 C-n 移 动 到 下 一 行 M-<(M 加 小 于 号 ) 移 动 光 标 到 整 个 文 本 的 开 头 M-f 向 前 移 动 一 个 单 词 M->(M 加 大 于 号 ) 移 动 光 标 到 整 个 文 本 的 末 尾 (2) 剪 切 和 粘 贴 在 emacs 中 可 以 使 用 Delete 和 BackSpace 删 除 光 标 前 后 的 字 符, 这 和 用 户 之 前 的 习 惯 一 致, 在 此 就 不 赘 述 以 词 和 行 为 单 位 的 剪 切 和 粘 贴 功 能 键 如 表 3.4 所 示 表 3.4 emacs 剪 切 和 粘 贴 功 能 键 功 能 功 能 键 功 能 M-Delete 剪 切 光 标 前 面 的 单 词 M-k 剪 切 从 光 标 位 置 到 句 尾 的 内 容 M-d 剪 切 光 标 前 面 的 单 词 C-y 将 缓 冲 区 中 的 内 容 粘 贴 到 光 标 所 在 的 位 置 C-k 剪 切 从 光 标 位 置 到 行 尾 的 内 容 C-x u 撤 销 操 作 ( 先 操 作 C+x, 接 着 再 单 击 u) 注 意 在 emacs 中 对 单 个 字 符 的 操 作 是 删 除, 而 对 词 和 句 的 操 作 是 剪 切, 即 保 存 在 缓 冲 区 中, 以 备 后 面 的 粘 贴 所 用 (3) 复 制 文 本 在 emacs 中 的 复 制 文 本 包 括 两 步 : 选 择 复 制 区 域 和 粘 贴 文 本 选 择 复 制 区 域 的 方 法 是 : 首 先 在 复 制 起 始 点 (A) 按 下 C-Space 或 C-@(C-Shift-2) 使 它 成 为 一 个 标 识 点, 再 将 光 标 移 至 复 制 结 束 点 ( B ), 再 按 下 M-w, 就 可 将 A 与 B 之 间 的 文 本 复 制 到 系 统 的 缓 冲 区 中 再 使 用 功 能 键 C-y 将 其 粘 贴 到 指 定 位 置 (4) 查 找 文 本

查 找 文 本 的 功 能 键 如 表 3.5 所 示 表 3.5 emacs 查 找 文 本 功 能 键 功 能 键 功 能 C-s C-r 查 找 光 标 以 后 的 内 容, 并 在 对 话 框 的 I-search: 后 输 入 要 查 找 的 字 符 串 查 找 光 标 以 前 的 内 容, 并 在 对 话 框 的 I-search backward: 后 输 入 要 查 找 的 字 符 串 (5) 保 存 文 档 在 emacs 中 保 存 文 档 的 功 能 键 为 C+x C+s ( 即 先 操 作 C+x, 接 着 再 操 作 C+s), 这 时, 屏 幕 底 下 的 对 话 框 会 出 现 如 Wrote /root/workplace/editor/why 的 字 样, 如 图 3.7 所 示 图 3.7 emacs 中 保 存 文 档 另 外,emacs 在 编 辑 时 会 为 每 个 文 件 提 供 自 动 保 存 (auto save) 的 机 制, 而 且 自 动 保 存 的 文 件 的 文 件 名 前 后 都 有 一 个 #, 例 如, 编 辑 名 为 hello.c 的 文 件, 其 自 动 保 存 的 文 件 的 文 件 名 就 叫 #hello.c# 当 用 户 正 常 地 保 存 了 文 件 后,emacs 就 会 删 除 这 个 自 动 保 存 的 文 件 这 个 机 制 当 系 统 发 生 异 常 时 非 常 有 用 (6) 退 出 文 档 在 emacs 中 退 出 文 档 的 功 能 键 为 C-x C-c 4.emacs 中 的 模 式 emacs 不 仅 仅 是 个 强 大 的 编 译 器, 它 还 是 一 个 集 编 译 调 试 等 于 一 体 的 工 作 环 境 在 这 里, 读 者 将 会 了 解 到 emacs 作 为 编 译 器 的 最 基 本 的 概 念, 感 兴 趣 的 读 者 可 以 参 考 Learning GNU Emacs,Second Edition 一 书 进 一 步 学 习 emacs

在 emacs 中 并 没 有 像 vi 中 那 样 的 命 令 行 编 辑 模 式, 只 有 一 种 编 辑 模 式 这 里 所 说 的 模 式 是 指 emacs 里 的 各 种 辅 助 环 境 下 面 着 重 讲 解 C 模 式 当 我 们 启 动 某 一 文 件 时,emacs 会 判 断 文 件 的 类 型, 从 而 自 动 选 择 相 应 的 模 式 当 然, 用 户 也 可 以 手 动 启 动 各 种 模 式, 用 功 能 键 M-x, 然 后 再 输 入 模 式 的 名 称, 如 图 3.8 所 示, 这 样 就 启 动 了 C 模 式 图 3.8 emacs 中 选 择 模 式 在 强 大 的 C 模 式 下, 用 户 拥 有 自 动 缩 进 注 释 预 处 理 扩 展 自 动 状 态 等 强 大 功 能 在 C 模 式 下 编 辑 代 码 时, 可 以 用 Tab 键 自 动 地 将 当 前 行 的 代 码 产 生 适 当 的 缩 进, 使 代 码 结 构 清 晰 美 观, 它 也 可 以 指 定 缩 进 的 规 则 源 代 码 要 有 良 好 的 可 读 性, 必 须 要 有 良 好 的 注 释 在 emacs 中, 用 M- 可 以 产 生 一 条 右 缩 进 的 注 释 C 模 式 下 是 /* comments */ 形 式 的 注 释,C++ 模 式 下 是 // comments 形 式 的 注 释 当 用 户 高 亮 选 定 某 段 文 本, 然 后 操 作 C-c C-c, 就 可 以 注 释 该 段 文 字 emacs 还 可 以 使 用 C 预 处 理 其 运 行 代 码 的 一 部 分, 以 便 让 程 序 员 检 测 宏 条 件 编 译 以 及 include 语 句 的 效 果 5.emacs 编 译 调 试 程 序 emacs 可 以 让 程 序 员 在 emacs 环 境 里 编 译 自 己 的 软 件 此 时, 编 辑 器 把 编 译 器 的 输 出 和 程 序 代 码 连 接 起 来 程 序 员 可 以 像 使 用 Windows 的 其 他 开 发 工 具 一 样, 将 出 错 位 置 和 代 码 定 位 联 系 起 来 emacs 默 认 的 编 辑 命 令 是 对 一 个 make( 在 本 章 3.6 节 中 会 详 细 介 绍 ) 的 调 用 用 户 可 以 打 开 tool 下 的 Compile 进 行 查 看 emacs 可 以 支 持 大 量 的 工 程 项 目, 以 方 便 程 序 员 的 开 发 另 外,emacs 为 gdb 调 试 器 提 供 了 一 个 功 能 齐 全 的 接 口 在 emacs 中 使 用 gdb 的 时 候, 程 序 员 不 仅 能 够 获 得 gdb 的 全 部 标 准 特 性, 还 可 以 获 得 通 过 接 口 增 强 而 产 生 的

其 他 性 能 嵌 入 式 Linux 应 用 程 序 开 发 标 准 教 程 第 3 章 Linux 下 C 编 程 基 础 3.3 gcc 编 译 器 GNU CC( 简 称 为 gcc) 是 GNU 项 目 中 符 合 ANSI C 标 准 的 编 译 系 统, 能 够 编 译 用 C C++ 和 Object C 等 语 言 编 写 的 程 序 gcc 不 仅 功 能 强 大, 而 且 可 以 编 译 如 C C++ Object C Java Fortran Pascal Modula-3 和 Ada 等 多 种 语 言, 而 且 gcc 是 一 个 交 叉 平 台 编 译 器, 它 能 够 在 当 前 CPU 平 台 上 为 多 种 不 同 体 系 结 构 的 硬 件 平 台 开 发 软 件, 因 此 尤 其 适 合 在 嵌 入 式 领 域 的 开 发 编 译 本 章 中 的 示 例, 除 非 特 别 注 明, 否 则 均 采 用 4.x.x 的 gcc 版 本 表 3.6 所 示 为 gcc 支 持 编 译 源 文 件 的 后 缀 及 其 解 释 表 3.6 gcc 所 支 持 后 缀 名 解 释 后 缀 名 所 对 应 的 语 言 后 缀 名 所 对 应 的 语 言.c C 原 始 程 序.s/.S 汇 编 语 言 原 始 程 序.C/.cc/.cxx C++ 原 始 程 序.h 预 处 理 文 件 ( 头 文 件 ).m Objective-C 原 始 程 序.o 目 标 文 件.i 已 经 过 预 处 理 的 C 原 始 程 序.a/.so 编 译 后 的 库 文 件.ii 已 经 过 预 处 理 的 C++ 原 始 程 序 3.3.1 gcc 编 译 流 程 解 析 如 本 章 开 头 提 到 的,gcc 的 编 译 流 程 分 为 了 4 个 步 骤, 分 别 为 : 预 处 理 (Pre-Processing); 编 译 (Compiling); 汇 编 (Assembling); 链 接 (Linking) 下 面 就 具 体 来 查 看 一 下 gcc 是 如 何 完 成 以 上 4 个 步 骤 的 首 先 看 一 下 hello.c 的 源 代 码 : #include <stdio.h> int main() { } printf("hello! This is our embedded world!\n"); return 0; (1) 预 处 理 阶 段 在 该 阶 段, 对 包 含 的 头 文 件 (#include) 和 宏 定 义 (#define #ifdef 等 ) 进 行 处 理 在 上 述 代 码 的 预 处 理 过 程 中, 编 译 器 将 包 含 的 头 文 件 stdio.h 编 译 进 来, 并 且 用 户 可 以 使 用 gcc 的 选 项 -E 进 行 查 看, 该 选 项 的 作 用 是 让 gcc 在 预 处 理 结 束 后 停 止 编 译 过

程 注 意 嵌 入 式 Linux 应 用 程 序 开 发 标 准 教 程 第 3 章 Linux 下 C 编 程 基 础 gcc 指 令 的 一 般 格 式 为 :gcc [ 选 项 ] 要 编 译 的 文 件 [ 选 项 ] [ 目 标 文 件 ] 其 中, 目 标 文 件 可 缺 省,gcc 默 认 生 成 可 执 行 的 文 件, 名 为 : 编 译 文 件.out [root@localhost gcc]# gcc E hello.c o hello.i 在 此 处, 选 项 -o 是 指 目 标 文 件, 由 表 3.6 可 知,.i 文 件 为 已 经 过 预 处 理 的 C 程 序 以 下 列 出 了 hello.i 文 件 的 部 分 内 容 : typedef int (* gconv_trans_fct) (struct gconv_step *, struct gconv_step_data *, void *, const unsigned char *, const unsigned char **, const unsigned char *, unsigned char **, size_t *); # 2 "hello.c" 2 int main() { } printf("hello! This is our embedded world!\n"); return 0; 由 此 可 见,gcc 确 实 进 行 了 预 处 理, 它 把 stdio.h 的 内 容 插 入 hello.i 文 件 中 (2) 编 译 阶 段 接 下 来 进 行 的 是 编 译 阶 段, 在 这 个 阶 段 中,gcc 首 先 要 检 查 代 码 的 规 范 性 是 否 有 语 法 错 误 等, 以 确 定 代 码 实 际 要 做 的 工 作, 在 检 查 无 误 后,gcc 把 代 码 翻 译 成 汇 编 语 言 用 户 可 以 使 用 -S 选 项 来 进 行 查 看, 该 选 项 只 进 行 编 译 而 不 进 行 汇 编, 结 果 生 成 汇 编 代 码 [root@localhost gcc]# gcc S hello.i o hello.s 以 下 列 出 了 hello.s 的 内 容, 可 见 gcc 已 经 将 其 转 化 为 汇 编 代 码 了, 感 兴 趣 的 读 者 可 以 分 析 一 下 这 一 个 简 单 的 C 语 言 小 程 序 是 如 何 用 汇 编 代 码 实 现 的.LC0:.file "hello.c".section.rodata.align 4.string.text.globl main.type main, @function main: pushl %ebp movl %esp, %ebp "Hello! This is our embedded world!"

subl $8, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax subl %eax, %esp subl $12, %esp pushl $.LC0 call puts addl $16, %esp movl $0, %eax leave ret.size main,.-main.ident "GCC: (GNU) 4.0.0 200XYZ19 (Red Hat 4.0.0-8)".section.note.GNU-stack,"",@progbits (3) 汇 编 阶 段 汇 编 阶 段 是 把 编 译 阶 段 生 成 的.s 文 件 转 成 目 标 文 件, 读 者 在 此 使 用 选 项 -c 就 可 看 到 汇 编 代 码 已 转 化 为.o 的 二 进 制 目 标 代 码 了, 如 下 所 示 : [root@localhost gcc]# gcc c hello.s o hello.o (4) 链 接 阶 段 在 成 功 编 译 之 后, 就 进 入 了 链 接 阶 段 这 里 涉 及 一 个 重 要 的 概 念 : 函 数 库 读 者 可 以 重 新 查 看 这 个 小 程 序, 在 这 个 程 序 中 并 没 有 定 义 printf 的 函 数 实 现, 且 在 预 编 译 中 包 含 进 的 stdio.h 中 也 只 有 该 函 数 的 声 明, 而 没 有 定 义 函 数 的 实 现, 那 么, 是 在 哪 里 实 现 printf 函 数 的 呢? 最 后 的 答 案 是 : 系 统 把 这 些 函 数 的 实 现 都 放 到 名 为 libc.so.6 的 库 文 件 中 去 了, 在 没 有 特 别 指 定 时,gcc 会 到 系 统 默 认 的 搜 索 路 径 /usr/lib 下 进 行 查 找, 也 就 是 链 接 到 libc.so.6 函 数 库 中 去, 这 样 就 能 调 用 函 数 printf 了, 而 这 也 正 是 链 接 的 作 用 函 数 库 有 静 态 库 和 动 态 库 两 种 静 态 库 是 指 编 译 链 接 时, 将 库 文 件 的 代 码 全 部 加 入 可 执 行 文 件 中, 因 此 生 成 的 文 件 比 较 大, 但 在 运 行 时 也 就 不 再 需 要 库 文 件 了 其 后 缀 名 通 常 为.a 动 态 库 与 之 相 反, 在 编 译 链 接 时 并 没 有 将 库 文 件 的 代 码 加 入 可 执 行 文 件 中, 而 是 在 程 序 执 行 时 加 载 库, 这 样 可 以 节 省 系 统 的 开 销 一 般 动 态 库 的 后 缀 名 为.so, 如 前 面 所 述 的 libc.so.6 就 是 动 态 库 gcc 在 编 译 时 默 认 使 用 动 态 库 完 成 了 链 接 之 后,gcc 就 可 以 生 成 可 执 行 文 件, 如 下 所 示 [root@localhost gcc]# gcc hello.o o hello 运 行 该 可 执 行 文 件, 出 现 的 正 确 结 果 如 下

[root@localhost gcc]#./hello Hello! This is our embedded world! 3.3.2 gcc 编 译 选 项 分 析 gcc 有 超 过 100 个 可 用 选 项, 主 要 包 括 总 体 选 项 告 警 和 出 错 选 项 优 化 选 项 和 体 系 结 构 相 关 选 项 以 下 对 每 一 类 中 最 常 用 的 选 项 进 行 讲 解 (1) 常 用 选 项 gcc 的 常 用 选 项 如 表 3.7 所 示, 很 多 在 前 面 的 示 例 中 已 经 有 所 涉 及 表 3.7 gcc 常 用 选 项 列 表 选 项 含 义 -c 只 编 译 不 链 接, 生 成 目 标 文 件.o -S 只 编 译 不 汇 编, 生 成 汇 编 代 码 -E 只 进 行 预 编 译, 不 做 其 他 处 理 -g 在 可 执 行 程 序 中 包 含 标 准 调 试 信 息 -o file 将 file 文 件 指 定 为 输 出 文 件 -v 打 印 出 编 译 器 内 部 编 译 各 过 程 的 命 令 行 信 息 和 编 译 器 的 版 本 -I dir 在 头 文 件 的 搜 索 路 径 列 表 中 添 加 dir 目 录 前 一 小 节 已 经 讲 解 了 -c -E -o -S 选 项 的 使 用 方 法, 在 此 主 要 讲 解 另 外 2 个 非 常 常 用 的 库 依 赖 选 项 -I dir -I dir 正 如 上 表 中 所 述, -I dir 选 项 可 以 在 头 文 件 的 搜 索 路 径 列 表 中 添 加 dir 目 录 由 于 Linux 中 头 文 件 都 默 认 放 到 了 /usr/include/ 目 录 下, 因 此, 当 用 户 希 望 添 加 放 置 在 其 他 位 置 的 头 文 件 时, 就 可 以 通 过 -I dir 选 项 来 指 定, 这 样,gcc 就 会 到 相 应 的 位 置 查 找 对 应 的 目 录 比 如 在 /root/workplace/gcc 下 有 两 个 文 件 : /* hello1.c */ #include<my.h> int main() { } printf("hello!!\n"); return 0; /* my.h */ #include<stdio.h> 这 样, 就 可 在 gcc 命 令 行 中 加 入 -I 选 项 : [root@localhost gcc] gcc hello1.c I /root/workplace/gcc/ -o hello1 这 样,gcc 就 能 够 执 行 出 正 确 结 果

小 知 识 嵌 入 式 Linux 应 用 程 序 开 发 标 准 教 程 第 3 章 Linux 下 C 编 程 基 础 在 include 语 句 中, <> 表 示 在 标 准 路 径 中 搜 索 头 文 件, 表 示 在 本 目 录 中 搜 索 故 在 上 例 中, 可 把 hello1.c 的 #include<my.h> 改 为 #include my.h 就 不 需 要 加 上 -I 选 项 了 (2) 库 选 项 gcc 库 选 项 如 表 3.8 所 示 表 3.8 gcc 库 选 项 列 表 选 项 含 义 -static -shared 进 行 静 态 编 译, 即 链 接 静 态 库, 禁 止 使 用 动 态 库 1. 可 以 生 成 动 态 库 文 件 2. 进 行 动 态 编 译, 尽 可 能 地 链 接 动 态 库, 只 有 当 没 有 动 态 库 时 才 会 链 接 同 名 的 静 态 库 ( 默 认 选 项, 即 可 省 略 ) -L dir 在 库 文 件 的 搜 索 路 径 列 表 中 添 加 dir 目 录 -lname -fpic( 或 -fpic) 链 接 称 为 libname.a( 静 态 库 ) 或 者 libname.so( 动 态 库 ) 的 库 文 件 若 两 个 库 都 存 在 则 根 据 编 译 方 式 (-static 还 是 -shared) 而 进 行 链 接 生 成 使 用 相 对 地 址 的 位 置 无 关 的 目 标 代 码 (Position Independent Code) 然 后 通 常 使 用 gcc 的 -static 选 项 从 该 PIC 目 标 文 件 生 成 动 态 库 文 件 我 们 通 常 需 要 将 一 些 常 用 的 公 共 函 数 编 译 并 集 成 到 二 进 制 文 件 (Linux 的 ELF 格 式 文 件 ), 以 便 其 他 程 序 可 重 复 地 使 用 该 文 件 中 的 函 数, 此 时 将 这 种 文 件 叫 做 函 数 库, 使 用 函 数 库 不 仅 能 够 节 省 很 多 内 存 和 存 储 器 的 空 间 资 源, 而 且 更 重 要 的 是 大 大 降 低 开 发 难 度 和 开 销, 提 高 开 发 效 率 并 增 强 程 序 的 结 构 性 实 际 上, 在 Linux 中 的 每 个 程 序 都 会 链 接 到 一 个 或 者 多 个 库 比 如 使 用 C 函 数 的 程 序 会 链 接 到 C 运 行 时 库,Qt 应 用 程 序 会 链 接 到 Qt 支 持 的 相 关 图 形 库 等 函 数 库 有 静 态 库 和 动 态 库 两 种, 静 态 库 是 一 系 列 的 目 标 文 件 (.o 文 件 ) 的 归 档 文 件 ( 文 件 名 格 式 为 libname.a), 如 果 在 编 译 某 个 程 序 时 链 接 静 态 库, 则 链 接 器 将 会 搜 索 静 态 库, 从 中 提 取 出 它 所 需 要 的 目 标 文 件 并 直 接 复 制 到 该 程 序 的 可 执 行 二 进 制 文 件 (ELF 格 式 文 件 ) 之 中 ; 动 态 库 ( 文 件 名 格 式 为 libname.so[. 主 版 本 号. 次 版 本 号. 发 行 号 ]) 在 程 序 编 译 时 并 不 会 被 链 接 到 目 标 代 码 中, 而 是 在 程 序 运 行 时 才 被 载 入 下 面 举 一 个 简 单 的 例 子, 讲 解 如 何 怎 么 创 建 和 使 用 这 两 种 函 数 库 首 先 创 建 unsgn_pow.c 文 件, 它 包 含 unsgn_pow() 函 数 的 定 义, 具 体 代 码 如 下 所 示 /* unsgn_pow.c: 库 程 序 */ unsigned long long unsgn_pow(unsigned int x, unsigned int y) { unsigned long long res = 1; if (y == 0) { res = 1; } else if (y == 1)

} 嵌 入 式 Linux 应 用 程 序 开 发 标 准 教 程 第 3 章 Linux 下 C 编 程 基 础 { res = x; } else { res = x * unsgn_pow(x, y - 1); } return res; 然 后 创 建 pow_test.c 文 件, 它 会 调 用 unsgn_pow() 函 数 /* pow_test.c */ #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { unsigned int x, y; unsigned long long res; if ((argc < 3) (sscanf(argv[1], "%u", &x)!= 1) (sscanf(argv[2], "%u", &y))!= 1) { printf("usage: pow base exponent\n"); exit(1); } res = unsgn_pow(x, y); printf("%u ^ %u = %u\n", x, y, res); exit(0); } 我 们 用 unsgn_pow.c 文 件 可 以 制 作 一 个 函 数 库 下 面 分 别 讲 解 怎 么 生 成 静 态 库 和 动 态 库 静 态 库 的 创 建 和 使 用 创 建 静 态 库 比 较 简 单, 使 用 归 档 工 具 ar 将 一 些 目 标 文 件 集 成 在 一 起 [root@localhost lib]# gcc -c unsgn_pow.c [root@localhost lib]# ar rcsv libpow.a unsgn_pow.o a - unsgn_pow.o 下 面 编 译 主 程 序, 它 将 会 链 接 到 刚 生 成 的 静 态 库 libpow.a 具 体 运 行 结 果 如 下 所 示 [root@localhost lib]# gcc -o pow_test pow_test.c -L. lpow

[root@localhost lib]#./pow_test 2 10 2 ^ 10 = 1024 其 中, 选 项 -L dir 的 功 能 与 -I dir 类 似, 能 够 在 库 文 件 的 搜 索 路 径 列 表 中 添 加 dir 目 录, 而 -lname 选 项 指 示 编 译 时 链 接 到 库 文 件 libname.a 或 者 libname.so 本 实 例 中, 程 序 pow_test.c 需 要 使 用 当 前 目 录 下 的 一 个 静 态 库 libpow.a 动 态 库 的 创 建 和 使 用 首 先 使 用 gcc 的 -fpic 选 项 为 动 态 库 构 造 一 个 目 标 文 件 [root@localhost lib]# gcc -fpic -Wall -c unsgn_pow.c 接 下 来, 使 用 -shared 选 项 和 已 创 建 的 位 置 无 关 目 标 代 码, 生 成 一 个 动 态 库 libpow.so [root@localhost lib]# gcc -shared -o libpow.so unsgn_pow.o 下 面 编 译 主 程 序, 它 将 会 链 接 到 刚 生 成 的 动 态 库 libpow.so [root@localhost lib]# gcc -o pow_test pow_test.c -L. lpow 在 运 行 可 执 行 程 序 之 前, 需 要 注 册 动 态 库 的 路 径 名 其 方 法 有 几 种 : 修 改 /etc/ld.so.conf 文 件, 或 者 修 改 LD_LIBRARY_PATH 环 境 变 量, 或 者 将 库 文 件 直 接 复 制 到 /lib 或 者 /usr/lib 目 录 下 ( 这 两 个 目 录 为 系 统 的 默 认 的 库 路 径 名 ) [root@localhost lib]# cp libpow.so /lib [root@localhost lib]#./pow_test 2 10 2 ^ 10 = 1024 动 态 库 只 有 当 使 用 它 的 程 序 执 行 时 才 被 链 接 使 用, 而 不 是 将 需 要 的 部 分 直 接 编 译 入 可 执 行 文 件 中, 并 且 一 个 动 态 库 可 以 被 多 个 程 序 使 用 故 可 称 为 共 享 库, 而 静 态 库 将 会 整 合 到 程 序 中, 因 此 在 程 序 执 行 时 不 用 加 载 静 态 库 从 而 可 知, 链 接 到 静 态 库 会 使 用 户 的 程 序 臃 肿, 并 且 难 以 升 级, 但 是 可 能 会 比 较 容 易 部 署 而 链 接 到 动 态 库 会 使 用 户 的 程 序 轻 便, 并 且 易 于 升 级, 但 是 会 难 以 部 署 (3) 告 警 和 出 错 选 项 gcc 的 告 警 和 出 错 选 项 如 表 3.9 所 示 表 3.9 gcc 警 告 和 出 错 选 项 选 项 列 表 选 项 含 义 -ansi -pedantic -pedantic-error 支 持 符 合 ANSI 标 准 的 C 程 序 允 许 发 出 ANSI C 标 准 所 列 的 全 部 警 告 信 息 允 许 发 出 ANSI C 标 准 所 列 的 全 部 错 误 信 息 -w 关 闭 所 有 告 警 -Wall -werror 允 许 发 出 gcc 提 供 的 所 有 有 用 的 报 警 信 息 把 所 有 的 告 警 信 息 转 化 为 错 误 信 息, 并 在 告 警 发 生 时 终 止 编 译 过 程 下 面 结 合 实 例 对 这 几 个 告 警 和 出 错 选 项 进 行 简 单 的 讲 解 有 以 下 程 序 段 :

#include<stdio.h> 嵌 入 式 Linux 应 用 程 序 开 发 标 准 教 程 第 3 章 Linux 下 C 编 程 基 础 void main() { } long long tmp = 1; printf("this is a bad code!\n"); return 0; 这 是 一 个 很 糟 糕 的 程 序, 读 者 可 以 考 虑 一 下 有 哪 些 问 题 -ansi 该 选 项 强 制 gcc 生 成 标 准 语 法 所 要 求 的 告 警 信 息, 尽 管 这 还 并 不 能 保 证 所 有 没 有 警 告 的 程 序 都 是 符 合 ANSI C 标 准 的 运 行 结 果 如 下 所 示 : [root@localhost gcc]# gcc ansi warning.c o warning warning.c: 在 函 数 main 中 : warning.c:7 警 告 : 在 无 返 回 值 的 函 数 中, return 带 返 回 值 warning.c:4 警 告 : main 的 返 回 类 型 不 是 int 可 以 看 出, 该 选 项 并 没 有 发 现 long long 这 个 无 效 数 据 类 型 的 错 误 -pedantic 打 印 ANSI C 标 准 所 列 出 的 全 部 警 告 信 息, 同 样 也 保 证 所 有 没 有 警 告 的 程 序 都 是 符 合 ANSI C 标 准 的 其 运 行 结 果 如 下 所 示 : 误 [root@localhost gcc]# gcc pedantic warning.c o warning warning.c: 在 函 数 main 中 : warning.c:5 警 告 :ISO C90 不 支 持 long long warning.c:7 警 告 : 在 无 返 回 值 的 函 数 中, return 带 返 回 值 warning.c:4 警 告 : main 的 返 回 类 型 不 是 int 可 以 看 出, 使 用 该 选 项 查 出 了 long long 这 个 无 效 数 据 类 型 的 错 误 -Wall 打 印 gcc 能 够 提 供 的 所 有 有 用 的 报 警 信 息 该 选 项 的 运 行 结 果 如 下 所 示 : [root@localhost gcc]# gcc Wall warning.c o warning warning.c:4 警 告 : main 的 返 回 类 型 不 是 int warning.c: 在 函 数 main 中 : warning.c:7 警 告 : 在 无 返 回 值 的 函 数 中, return 带 返 回 值 warning.c:5 警 告 : 未 使 用 的 变 量 tmp 使 用 -Wall 选 项 找 出 了 未 使 用 的 变 量 tmp, 但 它 并 没 有 找 出 无 效 数 据 类 型 的 错 另 外,gcc 还 可 以 利 用 选 项 对 单 独 的 常 见 错 误 分 别 指 定 警 告 (4) 优 化 选 项 gcc 可 以 对 代 码 进 行 优 化, 它 通 过 编 译 选 项 -On 来 控 制 优 化 代 码 的 生 成, 其 中

n 是 一 个 代 表 优 化 级 别 的 整 数 对 于 不 同 版 本 的 gcc 来 讲,n 的 取 值 范 围 及 其 对 应 的 优 化 效 果 可 能 并 不 完 全 相 同, 比 较 典 型 的 范 围 是 从 0 变 化 到 2 或 3 不 同 的 优 化 级 别 对 应 不 同 的 优 化 处 理 工 作 如 使 用 优 化 选 项 -O 主 要 进 行 线 程 跳 转 (Thread Jump) 和 延 迟 退 栈 (Deferred Stack Pops) 两 种 优 化 使 用 优 化 选 项 -O2 除 了 完 成 所 有 -O1 级 别 的 优 化 之 外, 同 时 还 要 进 行 一 些 额 外 的 调 整 工 作, 如 处 理 器 指 令 调 度 等 选 项 -O3 则 还 包 括 循 环 展 开 和 其 他 一 些 与 处 理 器 特 性 相 关 的 优 化 工 作 虽 然 优 化 选 项 可 以 加 速 代 码 的 运 行 速 度, 但 对 于 调 试 而 言 将 是 一 个 很 大 的 挑 战 因 为 代 码 在 经 过 优 化 之 后, 原 先 在 源 程 序 中 声 明 和 使 用 的 变 量 很 可 能 不 再 使 用, 控 制 流 也 可 能 会 突 然 跳 转 到 意 外 的 地 方, 循 环 语 句 也 有 可 能 因 为 循 环 展 开 而 变 得 到 处 都 有, 所 有 这 些 对 调 试 来 讲 都 将 是 一 场 噩 梦 所 以 笔 者 建 议 在 调 试 的 时 候 最 好 不 使 用 任 何 优 化 选 项, 只 有 当 程 序 在 最 终 发 行 的 时 候 才 考 虑 对 其 进 行 优 化 (5) 体 系 结 构 相 关 选 项 gcc 的 体 系 结 构 相 关 选 项 如 表 3.10 所 示 表 3.10 gcc 体 系 结 构 相 关 选 项 列 表 选 项 含 义 -mcpu=type -mieee-fp -mno-ieee-fp -msoft-float -mshort -mrtd 针 对 不 同 的 CPU 使 用 相 应 的 CPU 指 令 可 选 择 的 type 有 i386 i486 pentium 及 i686 使 用 IEEE 标 准 进 行 浮 点 数 的 比 较 不 使 用 IEEE 标 准 进 行 浮 点 数 的 比 较 输 出 包 含 浮 点 库 调 用 的 目 标 代 码 把 int 类 型 作 为 16 位 处 理, 相 当 于 short int 强 行 将 函 数 参 数 个 数 固 定 的 函 数 用 ret NUM 返 回, 节 省 调 用 函 数 的 一 条 指 令 这 些 体 系 结 构 相 关 选 项 在 嵌 入 式 的 设 计 中 会 有 较 多 的 应 用, 读 者 需 根 据 不 同 体 系 结 构 将 对 应 的 选 项 进 行 组 合 处 理 在 本 书 后 面 涉 及 具 体 实 例 时 将 会 有 针 对 性 的 讲 解 3.4 gdb 调 试 器 调 试 是 所 有 程 序 员 都 会 面 临 的 问 题 如 何 提 高 程 序 员 的 调 试 效 率, 更 好 更 快 地 定 位 程 序 中 的 问 题 从 而 加 快 程 序 开 发 的 进 度, 是 大 家 都 很 关 注 的 问 题 就 如 读 者 熟 知 的 Windows 下 的 一 些 调 试 工 具, 如 Visual Studio 自 带 的 设 置 断 点 单 步 跟 踪 等, 都 受 到 了 广 大 用 户 的 赞 赏 那 么, 在 Linux 下 有 什 么 很 好 的 调 试 工 具 呢? gdb 调 试 器 是 一 款 GNU 开 发 组 织 并 发 布 的 UNIX/Linux 下 的 程 序 调 试 工 具 虽 然, 它 没 有 图 形 化 的 友 好 界 面, 但 是 它 强 大 的 功 能 也 足 以 与 微 软 的 Visual Studio 等 工 具 媲 美 下 面 就 请 跟 随 笔 者 一 步 步 学 习 gdb 调 试 器 3.4.1 gdb 使 用 流 程 这 里 给 出 了 一 个 短 小 的 程 序, 由 此 带 领 读 者 熟 悉 gdb 的 使 用 流 程 建 议 读 者 能 够

动 手 实 际 操 作 一 下 首 先, 打 开 Linux 下 的 编 辑 器 vi 或 者 emacs, 编 辑 如 下 代 码 ( 由 于 为 了 更 好 地 熟 悉 gdb 的 操 作, 笔 者 在 此 使 用 vi 编 辑, 希 望 读 者 能 够 参 见 3.3 节 中 对 vi 的 介 绍, 并 熟 练 使 用 vi) /*test.c*/ #include <stdio.h> int sum(int m); int main() { int i, n = 0; sum(50); for(i = 1; i<= 50; i++) { n += i; } printf("the sum of 1-50 is %d \n", n ); } int sum(int m) { int i, n = 0; for (i = 1; i <= m; i++) { n += i; printf("the sum of 1-m is %d\n", n); } } 在 保 存 退 出 后 首 先 使 用 gcc 对 test.c 进 行 编 译, 注 意 一 定 要 加 上 选 项 -g, 这 样 编 译 出 的 可 执 行 代 码 中 才 包 含 调 试 信 息, 否 则 之 后 gdb 无 法 载 入 该 可 执 行 文 件 [root@localhost gdb]# gcc -g test.c -o test 虽 然 这 段 程 序 没 有 错 误, 但 调 试 完 全 正 确 的 程 序 可 以 更 加 了 解 gdb 的 使 用 流 程 接 下 来 就 启 动 gdb 进 行 调 试 注 意,gdb 进 行 调 试 的 是 可 执 行 文 件, 而 不 是 如.c 的 源 代 码, 因 此, 需 要 先 通 过 gcc 编 译 生 成 可 执 行 文 件 才 能 用 gdb 进 行 调 试 [root@localhost gdb]# gdb test GNU gdb Red Hat Linux (6.3.0.0-1.21rh) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain

conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu"...using host libthread_db library "/lib/libthread_db.so.1". (gdb) 可 以 看 出, 在 gdb 的 启 动 画 面 中 指 出 了 gdb 的 版 本 号 使 用 的 库 文 件 等 信 息, 接 下 来 就 进 入 了 由 ( gdb) 开 头 的 命 令 行 界 面 了 (1) 查 看 文 件 在 gdb 中 键 入 l ( list) 就 可 以 查 看 所 载 入 的 文 件, 如 下 所 示 注 意 在 gdb 的 命 令 中 都 可 使 用 缩 略 形 式 的 命 令, 如 l 代 表 list, b 代 表 breakpoint, p 代 表 print 等, 读 者 也 可 使 用 help 命 令 查 看 帮 助 信 息 (gdb) l 1 #include <stdio.h> 2 int sum(int m); 3 int main() 4 { 5 int i,n = 0; 6 sum(50); 7 for(i = 1; i <= 50; i++) 8 { 9 n += i; 10 } (gdb) l 11 printf("the sum of 1~50 is %d \n", n ); 12 13 } 14 int sum(int m) 15 { 16 int i, n = 0; 17 for(i = 1; i <= m; i++) 18 { 19 n += i; 20 } 21 printf("the sum of 1~m is = %d\n", n); 20 } 可 以 看 出,gdb 列 出 的 源 代 码 中 明 确 地 给 出 了 对 应 的 行 号, 这 样 就 可 以 大 大 地 方 便 代 码 的 定 位 (2) 设 置 断 点

设 置 断 点 是 调 试 程 序 中 一 个 非 常 重 要 的 手 段, 它 可 以 使 程 序 运 行 到 一 定 位 置 时 暂 停 因 此, 程 序 员 在 该 位 置 处 可 以 方 便 地 查 看 变 量 的 值 堆 栈 情 况 等, 从 而 找 出 代 码 的 症 结 所 在 在 gdb 中 设 置 断 点 非 常 简 单, 只 需 在 b 后 加 入 对 应 的 行 号 即 可 ( 这 是 最 常 用 的 方 式, 另 外 还 有 其 他 方 式 设 置 断 点 ), 如 下 所 示 : (gdb) b 6 Breakpoint 1 at 0x804846d: file test.c, line 6. 要 注 意 的 是, 在 gdb 中 利 用 行 号 设 置 断 点 是 指 代 码 运 行 到 对 应 行 之 前 将 其 停 止, 如 上 例 中, 代 码 运 行 到 第 6 行 之 前 暂 停 ( 并 没 有 运 行 第 6 行 ) (3) 查 看 断 点 情 况 在 设 置 完 断 点 之 后, 用 户 可 以 键 入 info b 来 查 看 设 置 断 点 情 况, 在 gdb 中 可 以 设 置 多 个 断 点 (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x0804846d in main at test.c:6 用 户 在 断 点 键 入 backrace ( 只 输 入 bt 即 可 ) 可 以 查 到 调 用 函 数 ( 堆 栈 ) 的 情 况, 这 个 功 能 在 程 序 调 试 之 中 使 用 非 常 广 泛, 经 常 用 于 排 除 错 误 或 者 监 视 调 用 堆 栈 的 情 况 行 */ (gdb) b 19 (gdb) c Breakpoin 2, sum(m=50) at test.c:19 19 printf( The sum of 1-m is %d\n, n); (gdb) bt #0 sum(m=50) at test.c:19 /* 停 在 test.c 的 sum() 函 数, 第 19 #1 0x080483e8 in main() at test.c:6 /* test.c 的 第 6 行 调 用 sum 函 数 */ (4) 运 行 代 码 接 下 来 就 可 运 行 代 码 了,gdb 默 认 从 首 行 开 始 运 行 代 码, 键 入 r ( run) 即 可 ( 若 想 从 程 序 中 指 定 行 开 始 运 行, 可 在 r 后 面 加 上 行 号 ) (gdb) r Starting program: /root/workplace/gdb/test Reading symbols from shared object read from target memory...done. Loaded system supplied DSO at 0x5fb000 Breakpoint 1, main () at test.c:6 6 sum(50); 可 以 看 到, 程 序 运 行 到 断 点 处 就 停 止 了

(5) 查 看 变 量 值 在 程 序 停 止 运 行 之 后, 程 序 员 所 要 做 的 工 作 是 查 看 断 点 处 的 相 关 变 量 值 在 gdb 中 键 入 p + 变 量 值 即 可, 如 下 所 示 : (gdb) p n $1 = 0 (gdb) p i $2 = 134518440 在 此 处, 为 什 么 变 量 i 的 值 为 如 此 奇 怪 的 一 个 数 字 呢? 原 因 就 在 于 程 序 是 在 断 点 设 置 的 对 应 行 之 前 停 止 的, 那 么 在 此 时, 并 没 有 把 i 的 数 值 赋 为 零, 而 只 是 一 个 随 机 的 数 字 但 变 量 n 是 在 第 4 行 赋 值 的, 故 在 此 时 已 经 为 零 小 技 巧 gdb 在 显 示 变 量 值 时 都 会 在 对 应 值 之 前 加 上 $N 标 记, 它 是 当 前 变 量 值 的 引 用 标 记, 所 以 以 后 若 想 再 次 引 用 此 变 量 就 可 以 直 接 写 作 $N, 而 无 需 写 冗 长 的 变 量 名 (6) 单 步 运 行 单 步 运 行 可 以 使 用 命 令 n ( next) 或 s ( step), 它 们 之 间 的 区 别 在 于 : 若 有 函 数 调 用 的 时 候, s 会 进 入 该 函 数 而 n 不 会 进 入 该 函 数 因 此, s 就 类 似 于 Uisual 等 工 具 中 的 step in, n 类 似 与 Uisual 等 工 具 中 的 step over 它 们 的 使 用 如 下 所 示 : (gdb) n The sum of 1-m is 1275 7 for (i = 1; i <= 50; i++) (gdb) s sum (m=50) at test.c:16 16 int i, n = 0; 可 见, 使 用 n 后, 程 序 显 示 函 数 sum() 的 运 行 结 果 并 向 下 执 行, 而 使 用 s 后 则 进 入 sum() 函 数 之 中 单 步 运 行 (7) 恢 复 程 序 运 行 在 查 看 完 所 需 变 量 及 堆 栈 情 况 后, 就 可 以 使 用 命 令 c ( continue) 恢 复 程 序 的 正 常 运 行 了 这 时, 它 会 把 剩 余 还 未 执 行 的 程 序 执 行 完, 并 显 示 剩 余 程 序 中 的 执 行 结 果 以 下 是 之 前 使 用 n 命 令 恢 复 后 的 执 行 结 果 : (gdb) c Continuing. The sum of 1-50 is :1275 Program exited with code 031. 可 以 看 出, 程 序 在 运 行 完 后 退 出, 之 后 程 序 处 于 停 止 状 态

小 知 识 嵌 入 式 Linux 应 用 程 序 开 发 标 准 教 程 第 3 章 Linux 下 C 编 程 基 础 在 gdb 中, 程 序 的 运 行 状 态 有 运 行 暂 停 和 停 止 3 种, 其 中 暂 停 状 态 为 程 序 遇 到 了 断 点 或 观 察 点 之 类 的, 程 序 暂 时 停 止 运 行, 而 此 时 函 数 的 地 址 函 数 参 数 函 数 内 的 局 部 变 量 都 会 被 压 入 栈 (Stack) 中 故 在 这 种 状 态 下 可 以 查 看 函 数 的 变 量 值 等 各 种 属 性 但 在 函 数 处 于 停 止 状 态 之 后, 栈 就 会 自 动 撤 消, 它 也 就 无 法 查 看 各 种 信 息 了 3.4.2 gdb 基 本 命 令 gdb 的 命 令 可 以 通 过 查 看 help 进 行 查 找, 由 于 gdb 的 命 令 很 多, 因 此 gdb 的 help 将 其 分 成 了 很 多 种 类 (class), 用 户 可 以 通 过 进 一 步 查 看 相 关 class 找 到 相 应 命 令, 如 下 所 示 : (gdb) help List of classes of commands: aliases -- Aliases of other commands breakpoints -- Making program stop at certain points data -- Examining data files -- Specifying and examining files internals -- Maintenance commands Type "help"followedbyaclassnameforalistofcommandsinthatclass. Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous. 上 述 列 出 了 gdb 各 个 分 类 的 命 令, 注 意 底 部 的 加 粗 部 分 说 明 其 为 分 类 命 令 接 下 来 可 以 具 体 查 找 各 分 类 的 命 令, 如 下 所 示 : (gdb) help data Examining data. List of commands: call -- Call a function in the program delete display -- Cancel some expressions to be displayed when program stops delete mem -- Delete memory region disabledisplay--disablesomeexpressionstobedisplayedwhenprogram stops Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous.

若 用 户 想 要 查 找 call 命 令, 就 可 键 入 help call (gdb) help call Call a function in the program. The argument is the function name and arguments, in the notation of the current working language. The result is printed and saved in the value history, if it is not void. 当 然, 若 用 户 已 知 命 令 名, 直 接 键 入 help [command] 也 是 可 以 的 gdb 中 的 命 令 主 要 分 为 以 下 几 类 : 工 作 环 境 相 关 命 令 设 置 断 点 与 恢 复 命 令 源 代 码 查 看 命 令 查 看 运 行 数 据 相 关 命 令 及 修 改 运 行 参 数 命 令 以 下 就 分 别 对 这 几 类 命 令 进 行 讲 解 1. 工 作 环 境 相 关 命 令 gdb 中 不 仅 可 以 调 试 所 运 行 的 程 序, 而 且 还 可 以 对 程 序 相 关 的 工 作 环 境 进 行 相 应 的 设 定, 甚 至 还 可 以 使 用 shell 中 的 命 令 进 行 相 关 的 操 作, 其 功 能 极 其 强 大 gdb 常 见 工 作 环 境 相 关 命 令 如 表 3.11 所 示 表 3.11 gdb 工 作 环 境 相 关 命 令 命 令 格 式 含 义 set args 运 行 时 的 参 数 指 定 运 行 时 参 数, 如 set args 2 show args 查 看 设 置 好 的 运 行 参 数 Path dir 设 定 程 序 的 运 行 路 径 show paths 查 看 程 序 的 运 行 路 径 set environment var [=value] 设 置 环 境 变 量 show environment [var] 查 看 环 境 变 量 cd dir 进 入 dir 目 录, 相 当 于 shell 中 的 cd 命 令 Pwd 显 示 当 前 工 作 目 录 shell command 运 行 shell 的 command 命 令 2. 设 置 断 点 与 恢 复 命 令 gdb 中 设 置 断 点 与 恢 复 的 常 见 命 令 如 表 3.12 所 示 表 3.12 gdb 设 置 断 点 与 恢 复 相 关 命 令 命 令 格 式 含 义 Info b break [ 文 件 名 :] 行 号 或 函 数 名 < 条 件 表 达 式 > tbreak [ 文 件 名 :] 行 号 或 函 数 名 < 条 件 表 达 式 > delete [ 断 点 号 ] 查 看 所 设 断 点 设 置 断 点 设 置 临 时 断 点, 到 达 后 被 自 动 删 除 删 除 指 定 断 点, 其 断 点 号 为 info b 中 的 第 一 栏 若 缺 省 断 点 号 则 删 除 所 有 断 点

disable [ 断 点 号 ] enable [ 断 点 号 ] condition [ 断 点 号 ] < 条 件 表 达 式 > ignore [ 断 点 号 ]<num> Step Next Finish C 停 止 指 定 断 点, 使 用 info b 仍 能 查 看 此 断 点 同 delete 一 样, 若 缺 省 断 点 号 则 停 止 所 有 断 点 激 活 指 定 断 点, 即 激 活 被 disable 停 止 的 断 点 修 改 对 应 断 点 的 条 件 在 程 序 执 行 中, 忽 略 对 应 断 点 num 次 单 步 恢 复 程 序 运 行, 且 进 入 函 数 调 用 单 步 恢 复 程 序 运 行, 但 不 进 入 函 数 调 用 运 行 程 序, 直 到 当 前 函 数 完 成 返 回 继 续 执 行 函 数, 直 到 函 数 结 束 或 遇 到 新 的 断 点 设 置 断 点 在 gdb 的 调 试 中 非 常 重 要, 下 面 着 重 讲 解 gdb 中 设 置 断 点 的 方 法 gdb 中 设 置 断 点 有 多 种 方 式 : 其 一 是 按 行 设 置 断 点 ; 另 外 还 可 以 设 置 函 数 断 点 和 条 件 断 点 下 面 具 体 介 绍 后 两 种 设 置 断 点 的 方 法 1 函 数 断 点 gdb 中 按 函 数 设 置 断 点 只 需 把 函 数 名 列 在 命 令 b 之 后, 如 下 所 示 : (gdb) b test.c:sum ( 可 以 简 化 为 b sum) Breakpoint 1 at 0x80484ba: file test.c, line 16. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x080484ba in sum at test.c:16 要 注 意 的 是, 此 时 的 断 点 实 际 是 在 函 数 的 定 义 处, 也 就 是 在 16 行 处 ( 注 意 第 16 行 还 未 执 行 ) 2 条 件 断 点 gdb 中 设 置 条 件 断 点 的 格 式 为 :b 行 数 或 函 数 名 if 表 达 式 具 体 实 例 如 下 所 示 : (gdb) b 8 if i==10 Breakpoint 1 at 0x804848c: file test.c, line 8. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x0804848c in main at test.c:8 stop only if i == 10 (gdb) r Starting program: /home/yul/test The sum of 1-m is 1275 Breakpoint 1, main () at test.c:9 9 n += i; (gdb) p i $1 = 10

可 以 看 到, 该 例 中 在 第 8 行 ( 也 就 是 运 行 完 第 7 行 的 for 循 环 ) 设 置 了 一 个 i==0 的 条 件 断 点, 在 程 序 运 行 之 后 可 以 看 出, 程 序 确 实 在 i 为 10 时 暂 停 运 行 3.gdb 中 源 码 查 看 相 关 命 令 在 gdb 中 可 以 查 看 源 码 以 方 便 其 他 操 作, 它 的 常 见 相 关 命 令 如 表 3.13 所 示 表 3.13 gdb 源 码 查 看 相 关 相 关 命 令 命 令 格 式 含 义 list < 行 号 > < 函 数 名 > file [ 文 件 名 ] forward-search 正 则 表 达 式 reverse-search 正 则 表 达 式 dir DIR show directories info line 查 看 指 定 位 置 代 码 加 载 指 定 文 件 源 代 码 的 前 向 搜 索 源 代 码 的 后 向 搜 索 将 路 径 DIR 添 加 到 源 文 件 搜 索 的 路 径 的 开 头 显 示 源 文 件 的 当 前 搜 索 路 径 显 示 加 载 到 gdb 内 存 中 的 代 码 4.gdb 中 查 看 运 行 数 据 相 关 命 令 gdb 中 查 看 运 行 数 据 是 指 当 程 序 处 于 运 行 或 暂 停 状 态 时, 可 以 查 看 的 变 量 及 表 达 式 的 信 息, 其 常 见 命 令 如 表 3.14 所 示 表 3.14 gdb 查 看 运 行 数 据 相 关 命 令 命 令 格 式 含 义 print 表 达 式 变 量 x <n/f/u> display 表 达 式 backtrace 查 看 程 序 运 行 时 对 应 表 达 式 和 变 量 的 值 查 看 内 存 变 量 内 容 其 中 n 为 整 数 表 示 显 示 内 存 的 长 度,f 表 示 显 示 的 格 式,u 表 示 从 当 前 地 址 往 后 请 求 显 示 的 字 节 数 设 定 在 单 步 运 行 或 其 他 情 况 中, 自 动 显 示 的 对 应 表 达 式 的 内 容 查 看 当 前 栈 的 情 况, 即 可 以 查 到 哪 些 被 调 用 的 函 数 尚 未 返 回 5.gdb 中 修 改 运 行 参 数 相 关 命 令 gdb 还 可 以 修 改 运 行 时 的 参 数, 并 使 该 变 量 按 照 用 户 当 前 输 入 的 值 继 续 运 行 它 的 设 置 方 法 为 : 在 单 步 执 行 的 过 程 中, 键 入 命 令 set 变 量 = 设 定 值 这 样, 在 此 之 后, 程 序 就 会 按 照 该 设 定 的 值 运 行 了 下 面, 笔 者 结 合 上 一 节 的 代 码 将 n 的 初 始 值 设 为 4, 其 代 码 如 下 所 示 : (gdb) b 7 Breakpoint 5 at 0x804847a: file test.c, line 7. (gdb) r Starting program: /home/yul/test

The sum of 1-m is 1275 嵌 入 式 Linux 应 用 程 序 开 发 标 准 教 程 第 3 章 Linux 下 C 编 程 基 础 Breakpoint 5, main () at test.c:7 7 for(i=1; i <= 50; i++) (gdb) set n=4 (gdb) c Continuing. The sum of 1-50 is 1279 Program exited with code 031. 可 以 看 到, 最 后 的 运 行 结 果 确 实 比 之 前 的 值 大 了 4 注 意 gdb 使 用 时 的 注 意 点 : 在 gcc 编 译 选 项 中 一 定 要 加 入 -g 只 有 在 代 码 处 于 运 行 或 暂 停 状 态 时 才 能 查 看 变 量 值 设 置 断 点 后 程 序 在 指 定 行 之 前 停 止 3.5 make 工 程 管 理 器 到 此 为 止, 读 者 已 经 了 解 了 如 何 在 Linux 下 使 用 编 辑 器 编 写 代 码, 如 何 使 用 gcc 把 代 码 编 译 成 可 执 行 文 件, 还 学 习 了 如 何 使 用 gdb 来 调 试 程 序, 那 么, 所 有 的 工 作 看 似 已 经 完 成 了, 为 什 么 还 需 要 make 这 个 工 程 管 理 器 呢? 所 谓 工 程 管 理 器, 顾 名 思 义, 是 用 于 管 理 较 多 的 文 件 读 者 可 以 试 想 一 下, 由 成 百 上 千 个 文 件 构 成 的 项 目, 如 果 其 中 只 有 一 个 或 少 数 几 个 文 件 进 行 了 修 改, 按 照 之 前 所 学 的 gcc 编 译 工 具, 就 不 得 不 把 这 所 有 的 文 件 重 新 编 译 一 遍, 因 为 编 译 器 并 不 知 道 哪 些 文 件 是 最 近 更 新 的, 而 只 知 道 需 要 包 含 这 些 文 件 才 能 把 源 代 码 编 译 成 可 执 行 文 件, 于 是, 程 序 员 就 不 得 不 重 新 输 入 数 目 如 此 庞 大 的 文 件 名 以 完 成 最 后 的 编 译 工 作 编 译 过 程 分 为 编 译 汇 编 链 接 阶 段, 其 中 编 译 阶 段 仅 检 查 语 法 错 误 以 及 函 数 与 变 量 是 否 被 正 确 地 声 明 了, 在 链 接 阶 段 则 主 要 完 成 函 数 链 接 和 全 局 变 量 的 链 接 因 此, 那 些 没 有 改 动 的 源 代 码 根 本 不 需 要 重 新 编 译, 而 只 要 把 它 们 重 新 链 接 进 去 就 可 以 了 所 以, 人 们 就 希 望 有 一 个 工 程 管 理 器 能 够 自 动 识 别 更 新 了 的 文 件 代 码, 而 不 需 要 重 复 输 入 冗 长 的 命 令 行, 这 样,make 工 程 管 理 器 就 应 运 而 生 了 实 际 上,make 工 程 管 理 器 也 就 是 个 自 动 编 译 管 理 器, 这 里 的 自 动 是 指 它 能 够 根 据 文 件 时 间 戳 自 动 发 现 更 新 过 的 文 件 而 减 少 编 译 的 工 作 量, 同 时, 它 通 过 读 入 makefile 文 件 的 内 容 来 执 行 大 量 的 编 译 工 作 用 户 只 需 编 写 一 次 简 单 的 编 译 语 句 就 可 以 了 它 大 大 提 高 了 实 际 项 目 的 工 作 效 率, 而 且 几 乎 所 有 Linux 下 的 项 目 编 程 均 会 涉 及 它, 希 望 读 者 能 够 认 真 学 习 本 节 内 容

3.5.1 makefile 基 本 结 构 makefile 是 make 读 入 的 惟 一 配 置 文 件, 因 此 本 节 的 内 容 实 际 就 是 讲 述 makefile 的 编 写 规 则 在 一 个 makefile 中 通 常 包 含 如 下 内 容 : 需 要 由 make 工 具 创 建 的 目 标 体 (target), 通 常 是 目 标 文 件 或 可 执 行 文 件 ; 要 创 建 的 目 标 体 所 依 赖 的 文 件 (dependency_file); 创 建 每 个 目 标 体 时 需 要 运 行 的 命 令 (command), 这 一 行 必 须 以 制 表 符 (tab 键 ) 开 头 它 的 格 式 为 : target: dependency_files command /* 该 行 必 须 以 tab 键 开 头 */ 例 如, 有 两 个 文 件 分 别 为 hello.c 和 hello.h, 创 建 的 目 标 体 为 hello.o, 执 行 的 命 令 为 gcc 编 译 指 令 :gcc c hello.c, 那 么, 对 应 的 makefile 就 可 以 写 为 : #The simplest example hello.o: hello.c hello.h gcc c hello.c o hello.o 接 着 就 可 以 使 用 make 了 使 用 make 的 格 式 为 :make target, 这 样 make 就 会 自 动 读 入 makefile( 也 可 以 是 首 字 母 大 写 的 Makefile) 并 执 行 对 应 target 的 command 语 句, 并 会 找 到 相 应 的 依 赖 文 件 如 下 所 示 : 体 [root@localhost makefile]# make hello.o gcc c hello.c o hello.o [root@localhost makefile]# ls hello.c hello.h hello.o makefile 可 以 看 到,makefile 执 行 了 hello.o 对 应 的 命 令 语 句, 并 生 成 了 hello.o 目 标 注 意 在 makefile 中 的 每 一 个 command 前 必 须 有 Tab 符, 否 则 在 运 行 make 命 令 时 会 出 错 3.5.2 makefile 变 量 上 面 示 例 的 makefile 在 实 际 中 是 几 乎 不 存 在 的, 因 为 它 过 于 简 单, 仅 包 含 两 个 文 件 和 一 个 命 令, 在 这 种 情 况 下 完 全 不 必 要 编 写 makefile 而 只 需 在 shell 中 直 接 输 入 即 可, 在 实 际 中 使 用 的 makefile 往 往 是 包 含 很 多 的 文 件 和 命 令 的, 这 也 是 makefile 产 生 的 原 因 下 面 就 可 给 出 稍 微 复 杂 一 些 的 makefile 进 行 讲 解 david:kang.o yul.o gcc kang.o bar.o -o myprog kang.o : kang.c kang.h head.h gcc Wall O -g c kang.c -o kang.o yul.o : bar.c head.h

gcc - Wall O -g c yul.c -o yul.o 在 这 个 makefile 中 有 3 个 目 标 体 (target), 分 别 为 david kang.o 和 yul.o, 其 中 第 一 个 目 标 体 的 依 赖 文 件 就 是 后 两 个 目 标 体 如 果 用 户 使 用 命 令 make david, 则 make 管 理 器 就 是 找 到 david 目 标 体 开 始 执 行 这 时,make 会 自 动 检 查 相 关 文 件 的 时 间 戳 首 先, 在 检 查 kang.o yul.o 和 david 3 个 文 件 的 时 间 戳 之 前, 它 会 向 下 查 找 那 些 把 kang.o 或 yul.o 作 为 目 标 文 件 的 时 间 戳 比 如, kang.o 的 依 赖 文 件 为 kang.c kang.h head.h 如 果 这 些 文 件 中 任 何 一 个 的 时 间 戳 比 kang.o 新, 则 命 令 gcc Wall O -g c kang.c -o kang.o 将 会 执 行, 从 而 更 新 文 件 kang.o 在 更 新 完 kang.o 或 yul.o 之 后, make 会 检 查 最 初 的 kang.o yul.o 和 david 3 个 文 件, 只 要 文 件 kang.o 或 yul.o 中 的 至 少 有 一 个 文 件 的 时 间 戳 比 david 新, 则 第 二 行 命 令 就 会 被 执 行 这 样,make 就 完 成 了 自 动 检 查 时 间 戳 的 工 作, 开 始 执 行 编 译 工 作 这 也 就 是 make 工 作 的 基 本 流 程 接 下 来, 为 了 进 一 步 简 化 编 辑 和 维 护 makefile,make 允 许 在 makefile 中 创 建 和 使 用 变 量 变 量 是 在 makefile 中 定 义 的 名 字, 用 来 代 替 一 个 文 本 字 符 串, 该 文 本 字 符 串 称 为 该 变 量 的 值 在 具 体 要 求 下, 这 些 值 可 以 代 替 目 标 体 依 赖 文 件 命 令 以 及 makefile 文 件 中 其 他 部 分 在 makefile 中 的 变 量 定 义 有 两 种 方 式 : 一 种 是 递 归 展 开 方 式, 另 一 种 是 简 单 方 式 递 归 展 开 方 式 定 义 的 变 量 是 在 引 用 该 变 量 时 进 行 替 换 的, 即 如 果 该 变 量 包 含 了 对 其 他 变 量 的 引 用, 则 在 引 用 该 变 量 时 一 次 性 将 内 嵌 的 变 量 全 部 展 开, 虽 然 这 种 类 型 的 变 量 能 够 很 好 地 完 成 用 户 的 指 令, 但 是 它 也 有 严 重 的 缺 点, 如 不 能 在 变 量 后 追 加 内 容 ( 因 为 语 句 :CFLAGS = $(CFLAGS) -O 在 变 量 扩 展 过 程 中 可 能 导 致 无 穷 循 环 ) 为 了 避 免 上 述 问 题, 简 单 扩 展 型 变 量 的 值 在 定 义 处 展 开, 并 且 只 展 开 一 次, 因 此 它 不 包 含 任 何 对 其 他 变 量 的 引 用, 从 而 消 除 变 量 的 嵌 套 引 用 递 归 展 开 方 式 的 定 义 格 式 为 :VAR=var 简 单 扩 展 方 式 的 定 义 格 式 为 :VAR:=var make 中 的 变 量 使 用 均 使 用 的 格 式 为 :$(VAR) 注 意 变 量 名 是 不 包 括 : # = 以 及 结 尾 空 格 的 任 何 字 符 串 同 时, 变 量 名 中 包 含 字 母 数 字 以 及 下 划 线 以 外 的 情 况 应 尽 量 避 免, 因 为 它 们 可 能 在 将 来 被 赋 予 特 别 的 含 义 变 量 名 是 大 小 写 敏 感 的, 例 如 变 量 名 foo FOO 和 Foo 代 表 不 同 的 变 量 推 荐 在 makefile 内 部 使 用 小 写 字 母 作 为 变 量 名, 预 留 大 写 字 母 作 为 控 制 隐 含 规 则 参 数 或 用 户 重 载 命 令 选 项 参 数 的 变 量 名 下 面 给 出 了 上 例 中 用 变 量 替 换 修 改 后 的 makefile, 这 里 用 OBJS 代 替 kang.o 和 yul.o, 用 CC 代 替 gcc, 用 CFLAGS 代 替 -Wall -O g 这 样 在 以 后 修 改 时, 就 可 以 只 修 改 变 量 定 义, 而 不 需 要 修 改 下 面 的 定 义 实 体, 从 而 大 大 简 化 了 makefile 维 护 的 工

作 量 经 变 量 替 换 后 的 makefile 如 下 所 示 : OBJS = kang.o yul.o CC = gcc CFLAGS = -Wall -O -g david : $(OBJS) $(CC) $(OBJS) -o david kang.o : kang.c kang.h $(CC) $(CFLAGS) -c kang.c -o kang.o yul.o : yul.c yul.h $(CC) $(CFLAGS) -c yul.c -o yul.o 可 以 看 到, 此 处 变 量 是 以 递 归 展 开 方 式 定 义 的 makefile 中 的 变 量 分 为 用 户 自 定 义 变 量 预 定 义 变 量 自 动 变 量 及 环 境 变 量 如 上 例 中 的 OBJS 就 是 用 户 自 定 义 变 量, 自 定 义 变 量 的 值 由 用 户 自 行 设 定, 而 预 定 义 变 量 和 自 动 变 量 为 通 常 在 makefile 都 会 出 现 的 变 量, 它 们 的 一 部 分 有 默 认 值, 也 就 是 常 见 的 设 定 值, 当 然 用 户 可 以 对 其 进 行 修 改 预 定 义 变 量 包 含 了 常 见 编 译 器 汇 编 器 的 名 称 及 其 编 译 选 项 表 3.15 列 出 了 makefile 中 常 见 预 定 义 变 量 及 其 部 分 默 认 值 表 3.15 makefile 中 常 见 的 预 定 义 变 量 预 定 义 变 量 含 义 AR AS CC 库 文 件 维 护 程 序 的 名 称, 默 认 值 为 ar 汇 编 程 序 的 名 称, 默 认 值 为 as C 编 译 器 的 名 称, 默 认 值 为 cc CPP C 预 编 译 器 的 名 称, 默 认 值 为 $(CC) E CXX FC C++ 编 译 器 的 名 称, 默 认 值 为 g++ Fortran 编 译 器 的 名 称, 默 认 值 为 f77 RM 文 件 删 除 程 序 的 名 称, 默 认 值 为 rm f ARFLAGS ASFLAGS CFLAGS CPPFLAGS CXXFLAGS FFLAGS 库 文 件 维 护 程 序 的 选 项, 无 默 认 值 汇 编 程 序 的 选 项, 无 默 认 值 C 编 译 器 的 选 项, 无 默 认 值 C 预 编 译 的 选 项, 无 默 认 值 C++ 编 译 器 的 选 项, 无 默 认 值 Fortran 编 译 器 的 选 项, 无 默 认 值 可 以 看 出, 上 例 中 的 CC 和 CFLAGS 是 预 定 义 变 量, 其 中 由 于 CC 没 有 采 用 默 认 值, 因 此, 需 要 把 CC=gcc 明 确 列 出 来 由 于 常 见 的 gcc 编 译 语 句 中 通 常 包 含 了 目 标 文 件 和 依 赖 文 件, 而 这 些 文 件 在

makefile 文 件 中 目 标 体 所 在 行 已 经 有 所 体 现, 因 此, 为 了 进 一 步 简 化 makefile 的 编 写, 就 引 入 了 自 动 变 量 自 动 变 量 通 常 可 以 代 表 编 译 语 句 中 出 现 目 标 文 件 和 依 赖 文 件 等, 并 且 具 有 本 地 含 义 ( 即 下 一 语 句 中 出 现 的 相 同 变 量 代 表 的 是 下 一 语 句 的 目 标 文 件 和 依 赖 文 件 ) 表 3.16 列 出 了 makefile 中 常 见 的 自 动 变 量 表 3.16 makefile 中 常 见 的 自 动 变 量 自 动 变 量 含 义 $* 不 包 含 扩 展 名 的 目 标 文 件 名 称 $+ 所 有 的 依 赖 文 件, 以 空 格 分 开, 并 以 出 现 的 先 后 为 序, 可 能 包 含 重 复 的 依 赖 文 件 $< 第 一 个 依 赖 文 件 的 名 称 $? 所 有 时 间 戳 比 目 标 文 件 晚 的 依 赖 文 件, 并 以 空 格 分 开 $@ 目 标 文 件 的 完 整 名 称 $^ 所 有 不 重 复 的 依 赖 文 件, 以 空 格 分 开 $% 如 果 目 标 是 归 档 成 员, 则 该 变 量 表 示 目 标 的 归 档 成 员 名 称 自 动 变 量 的 书 写 比 较 难 记, 但 是 在 熟 练 了 之 后 使 用 会 非 常 方 便, 请 读 者 结 合 下 例 中 的 自 动 变 量 改 写 的 makefile 进 行 记 忆 OBJS = kang.o yul.o CC = gcc CFLAGS = -Wall -O -g david : $(OBJS) $(CC) $^ -o $@ kang.o : kang.c kang.h $(CC) $(CFLAGS) -c $< -o $@ yul.o : yul.c yul.h $(CC) $(CFLAGS) -c $< -o $@ 另 外, 在 makefile 中 还 可 以 使 用 环 境 变 量 使 用 环 境 变 量 的 方 法 相 对 比 较 简 单, make 在 启 动 时 会 自 动 读 取 系 统 当 前 已 经 定 义 了 的 环 境 变 量, 并 且 会 创 建 与 之 具 有 相 同 名 称 和 数 值 的 变 量 但 是, 如 果 用 户 在 makefile 中 定 义 了 相 同 名 称 的 变 量, 那 么 用 户 自 定 义 变 量 将 会 覆 盖 同 名 的 环 境 变 量 3.5.3 makefile 规 则 makefile 的 规 则 是 make 进 行 处 理 的 依 据, 它 包 括 了 目 标 体 依 赖 文 件 及 其 之 间 的 命 令 语 句 在 上 面 的 例 子 中, 都 显 式 地 指 出 了 makefile 中 的 规 则 关 系, 如 $(CC) $(CFLAGS) -c $< -o $@, 但 为 了 简 化 makefile 的 编 写,make 还 定 义 了 隐 式 规 则 和 模 式 规 则, 下 面 就 分 别 对 其 进 行 讲 解 1. 隐 式 规 则 隐 含 规 则 能 够 告 诉 make 怎 样 使 用 传 统 的 规 则 完 成 任 务, 这 样, 当 用 户 使 用 它 们

时 就 不 必 详 细 指 定 编 译 的 具 体 细 节, 而 只 需 把 目 标 文 件 列 出 即 可 make 会 自 动 搜 索 隐 式 规 则 目 录 来 确 定 如 何 生 成 目 标 文 件 如 上 例 就 可 以 写 成 : OBJS = kang.o yul.o CC = gcc CFLAGS = -Wall -O -g david : $(OBJS) $(CC) $^ -o $@ 为 什 么 可 以 省 略 后 两 句 呢? 因 为 make 的 隐 式 规 则 指 出 : 所 有.o 文 件 都 可 自 动 由.c 文 件 使 用 命 令 $(CC) $(CPPFLAGS) $(CFLAGS) -c file.c o file.o 来 生 成 这 样 kang.o 和 yul.o 就 会 分 别 通 过 调 用 $(CC) $(CFLAGS) -c kang.c -o kang.o 和 $(CC) $(CFLAGS) -c yul.c -o yul.o 来 生 成 注 意 在 隐 式 规 则 只 能 查 找 到 相 同 文 件 名 的 不 同 后 缀 名 文 件, 如 kang.o 文 件 必 须 由 kang.c 文 件 生 成 表 3.17 给 出 了 常 见 的 隐 式 规 则 目 录 表 3.17 对 应 语 言 后 缀 名 C 编 译 :.c 变 为.o C++ 编 译 :.cc 或.C 变 为.o Pascal 编 译 :.p 变 为.o Fortran 编 译 :.r 变 为 -o makefile 中 常 见 隐 式 规 则 目 录 隐 式 规 则 $(CC) c $(CPPFLAGS) $(CFLAGS) $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $(PC) -c $(PFLAGS) $(FC) -c $(FFLAGS) 2. 模 式 规 则 模 式 规 则 是 用 来 定 义 相 同 处 理 规 则 的 多 个 文 件 的 它 不 同 于 隐 式 规 则, 隐 式 规 则 仅 仅 能 够 用 make 默 认 的 变 量 来 进 行 操 作, 而 模 式 规 则 还 能 引 入 用 户 自 定 义 变 量, 为 多 个 文 件 建 立 相 同 的 规 则, 从 而 简 化 makefile 的 编 写 模 式 规 则 的 格 式 类 似 于 普 通 规 则, 这 个 规 则 中 的 相 关 文 件 前 必 须 用 % 标 明 使 用 模 式 规 则 修 改 后 的 makefile 的 编 写 如 下 : OBJS = kang.o yul.o CC = gcc CFLAGS = -Wall -O -g david : $(OBJS) %.o : %.c $(CC) $^ -o $@ $(CC) $(CFLAGS) -c $< -o $@ 3.5.4 make 管 理 器 的 使 用 使 用 make 管 理 器 非 常 简 单, 只 需 在 make 命 令 的 后 面 键 入 目 标 名 即 可 建 立 指 定 的 目 标, 如 果 直 接 运 行 make, 则 建 立 makefile 中 的 第 一 个 目 标

此 外 make 还 有 丰 富 的 命 令 行 选 项, 可 以 完 成 各 种 不 同 的 功 能 表 3.18 列 出 了 常 用 的 make 命 令 行 选 项 表 3.18 make 的 命 令 行 选 项 命 令 格 式 含 义 -C dir 读 入 指 定 目 录 下 的 makefile -f file 读 入 当 前 目 录 下 的 file 文 件 作 为 makefile -I 忽 略 所 有 的 命 令 执 行 错 误 -I dir 指 定 被 包 含 的 makefile 所 在 目 录 -n 只 打 印 要 执 行 的 命 令, 但 不 执 行 这 些 命 令 -p 显 示 make 变 量 数 据 库 和 隐 含 规 则 -s 在 执 行 命 令 时 不 显 示 命 令 -w 如 果 make 在 执 行 过 程 中 改 变 目 录, 则 打 印 当 前 目 录 名 3.6 使 用 autotools 在 上 一 小 节, 读 者 已 经 了 解 到 了 make 项 目 管 理 器 的 强 大 功 能 的 确,makefile 可 以 帮 助 make 完 成 它 的 使 命, 但 要 承 认 的 是, 编 写 makefile 确 实 不 是 一 件 轻 松 的 事, 尤 其 对 于 一 个 较 大 的 项 目 而 言 更 是 如 此 那 么, 有 没 有 一 种 轻 松 的 手 段 生 成 makefile 而 同 时 又 能 让 用 户 享 受 make 的 优 越 性 呢? 本 节 要 讲 的 autotools 系 列 工 具 正 是 为 此 而 设 的, 它 只 需 用 户 输 入 简 单 的 目 标 文 件 依 赖 文 件 文 件 目 录 等 就 可 以 轻 松 地 生 成 makefile 了, 这 无 疑 是 广 大 用 户 所 希 望 的 另 外, 这 些 工 具 还 可 以 完 成 系 统 配 置 信 息 的 收 集, 从 而 可 以 方 便 地 处 理 各 种 移 植 性 的 问 题 也 正 是 基 于 此, 现 在 Linux 上 的 软 件 开 发 一 般 都 用 autotools 来 制 作 makefile, 读 者 在 后 面 的 讲 述 中 就 会 了 解 到 3.6.1 autotools 使 用 流 程 正 如 前 面 所 言,autotools 是 系 列 工 具, 读 者 首 先 要 确 认 系 统 是 否 装 了 以 下 工 具 ( 可 以 用 which 命 令 进 行 查 看 ) 这 样 的 aclocal autoscan autoconf autoheader automake 使 用 autotools 主 要 就 是 利 用 各 个 工 具 的 脚 本 文 件 以 生 成 最 后 的 makefile 其 总 体 流 程 是 使 用 aclocal 生 成 一 个 aclocal.m4 文 件, 该 文 件 主 要 处 理 本 地 的 宏 定 义 ; 改 写 configure.scan 文 件, 并 将 其 重 命 名 为 configure.in, 并 使 用 autoconf 文 件 生 成 configure 文 件

接 下 来, 笔 者 将 通 过 一 个 简 单 的 hello.c 例 子 带 领 读 者 熟 悉 autotools 生 成 makefile 的 过 程, 由 于 在 这 过 程 中 会 涉 及 较 多 的 脚 本 文 件, 为 了 更 清 楚 地 了 解 相 互 之 间 的 关 系, 强 烈 建 议 读 者 实 际 动 手 操 作 以 体 会 其 整 个 过 程 1.autoscan 它 会 在 给 定 目 录 及 其 子 目 录 树 中 检 查 源 文 件, 若 没 有 给 出 目 录, 就 在 当 前 目 录 及 其 子 目 录 树 中 进 行 检 查 它 会 搜 索 源 文 件 以 寻 找 一 般 的 移 植 性 问 题 并 创 建 一 个 文 件 configure.scan, 该 文 件 就 是 接 下 来 autoconf 要 用 到 的 configure.in 原 型 如 下 所 示 : [root@localhost automake]# autoscan autom4te: configure.ac: no such file or directory autoscan: /usr/bin/autom4te failed with exit status: 1 [root@localhost automake]# ls autoscan.log configure.scan hello.c 由 上 述 代 码 可 知 autoscan 首 先 会 尝 试 去 读 入 configure.ac ( 同 configure.in 的 配 置 文 件 ) 文 件, 此 时 还 没 有 创 建 该 配 置 文 件, 于 是 它 会 自 动 生 成 一 个 configure.in 的 原 型 文 件 configure.scan 2.autoconf configure.in 是 autoconf 的 脚 本 配 置 文 件, 它 的 原 型 文 件 configure.scan 如 下 所 示 : # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) #The next one is modified by david #AC_INIT(FULL-PACKAGE-NAME,VERSION,BUG-REPORT-ADDRESS) AC_INIT(hello,1.0) # The next one is added by david AM_INIT_AUTOMAKE(hello,1.0) AC_CONFIG_SRCDIR([hello.c]) AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_CONFIG_FILES([makefile])

AC_OUTPUT 嵌 入 式 Linux 应 用 程 序 开 发 标 准 教 程 第 3 章 Linux 下 C 编 程 基 础 下 面 对 这 个 脚 本 文 件 进 行 解 释 以 # 号 开 始 的 行 是 注 释 AC_PREREQ 宏 声 明 本 文 件 要 求 的 autoconf 版 本, 如 本 例 使 用 的 版 本 2.59 AC_INIT 宏 用 来 定 义 软 件 的 名 称 和 版 本 等 信 息, 在 本 例 中 省 略 了 BUG-REPORT-ADDRESS, 一 般 为 作 者 的 E-mail AM_INIT_AUTOMAKE 是 笔 者 另 加 的, 它 是 automake 所 必 备 的 宏, 使 automake 自 动 生 成 makefile.in, 也 同 前 面 一 样,PACKAGE 是 所 要 产 生 软 件 套 件 的 名 称,VERSION 是 版 本 编 号 AC_CONFIG_SRCDIR 宏 用 来 检 查 所 指 定 的 源 码 文 件 是 否 存 在, 以 及 确 定 源 码 目 录 的 有 效 性 在 此 处 源 码 文 件 为 当 前 目 录 下 的 hello.c AC_CONFIG_HEADER 宏 用 于 生 成 config.h 文 件, 以 便 autoheader 使 用 AC_CONFIG_FILES 宏 用 于 生 成 相 应 的 makefile 文 件 中 间 的 注 释 之 间 可 以 分 别 添 加 用 户 测 试 程 序 测 试 函 数 库 测 试 头 文 件 等 宏 定 义 接 下 来 首 先 运 行 aclocal, 生 成 一 个 aclocal.m4 文 件, 该 文 件 主 要 处 理 本 地 的 宏 定 义 如 下 所 示 : [root@localhost automake]# aclocal 再 接 着 运 行 autoconf, 生 成 configure 可 执 行 文 件 如 下 所 示 : [root@localhost automake]# autoconf [root@localhost automake]# ls aclocal.m4 autom4te.cache autoscan.log configure configure.in hello.c 3.autoheader 接 着 使 用 autoheader 命 令, 它 负 责 生 成 config.h.in 文 件 该 工 具 通 常 会 从 acconfig.h 文 件 中 复 制 用 户 附 加 的 符 号 定 义, 因 为 这 里 没 有 附 加 符 号 定 义, 所 以 不 需 要 创 建 acconfig.h 文 件 如 下 所 示 : [root@localhost automake]# autoheader 4.automake 这 一 步 是 创 建 makefile 很 重 要 的 一 步,automake 要 用 的 脚 本 配 置 文 件 是 makefile.am, 用 户 需 要 自 己 创 建 相 应 的 文 件 之 后,automake 工 具 转 换 成 makefile.in 在 该 例 中, 笔 者 创 建 的 文 件 为 makefile.am, 如 下 所 示 : AUTOMAKE_OPTIONS=foreign bin_programs= hello

hello_sources= hello.c 下 面 对 该 脚 本 文 件 的 对 应 项 进 行 解 释 其 中 的 AUTOMAKE_OPTIONS 为 设 置 automake 的 选 项 GNU 对 自 己 发 布 的 软 件 有 严 格 的 规 范, 比 如 必 须 附 带 许 可 证 声 明 文 件 COPYING 等, 否 则 automake 执 行 时 会 报 错 automake 提 供 了 3 种 软 件 等 级 :foreign gnu 和 gnits, 让 用 户 选 择 采 用, 默 认 等 级 为 gnu 在 本 示 例 中 采 用 foreign 等 级, 它 只 检 测 必 须 的 文 件 bin_programs 定 义 要 产 生 的 执 行 文 件 名 如 果 要 产 生 多 个 执 行 文 件, 每 个 文 件 名 用 空 格 隔 开 hello_sources 定 义 hello 这 个 执 行 程 序 所 需 要 的 原 始 文 件 如 果 hello 这 个 程 序 是 由 多 个 原 始 文 件 所 产 生 的, 则 必 须 把 它 所 用 到 的 所 有 原 始 文 件 都 列 出 来, 并 用 空 格 隔 开 例 如 : 若 目 标 体 hello 需 要 hello.c david.c hello.h 三 个 依 赖 文 件, 则 定 义 hello_sources=hello.c david.c hello.h 要 注 意 的 是, 如 果 要 定 义 多 个 执 行 文 件, 则 对 每 个 执 行 程 序 都 要 定 义 相 应 的 file_sources 接 下 来 可 以 使 用 automake 命 令 来 生 成 configure.in 文 件, 在 这 里 使 用 选 项 -a ( 或 者 adding-missing ) 可 以 让 automake 自 动 添 加 一 些 必 需 的 脚 本 文 件 如 下 所 示 : [root@localhost automake]# automake a( 或 者 automake --add-missing) configure.in: installing './install-sh' configure.in: installing './missing' makefile.am: installing 'depcomp' [root@localhost automake]# ls aclocal.m4 autoscan.log configure.in hello.c makefile.am missing autom4te.cache configure depcomp install-sh makefile.in config.h.in 可 以 看 到, 在 automake 之 后 就 可 以 生 成 configure.in 文 件 5. 运 行 configure 在 这 一 步 中, 通 过 运 行 自 动 配 置 设 置 文 件 configure, 把 makefile.in 变 成 了 最 终 的 makefile 如 下 所 示 : [root@localhost automake]#./configure checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for gcc... gcc checking for C compiler default output file name... a.out

checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for style of include used by make... GNU checking dependency style of gcc... gcc3 configure: creating./config.status config.status: creating makefile config.status: executing depfiles commands 可 以 看 到, 在 运 行 configure 时 收 集 了 系 统 的 信 息, 用 户 可 以 在 configure 命 令 中 对 其 进 行 方 便 的 配 置 在./configure 的 自 定 义 参 数 有 两 种, 一 种 是 开 关 式 (--enable-xxx 或 --disable-xxx), 另 一 种 是 开 放 式, 即 后 面 要 填 入 一 串 字 符 (--with-xxx=yyyy) 参 数 读 者 可 以 自 行 尝 试 其 使 用 方 法 另 外, 读 者 可 以 查 看 同 一 目 录 下 的 config.log 文 件, 以 方 便 调 试 之 用 到 此 为 止,makefile 就 可 以 自 动 生 成 了 回 忆 整 个 步 骤, 用 户 不 再 需 要 定 制 不 同 的 规 则, 而 只 需 要 输 入 简 单 的 文 件 及 目 录 名 即 可, 这 样 就 大 大 方 便 了 用 户 的 使 用 autotools 生 成 makefile 的 流 程 如 图 3.9 所 示 autoscan aclocal configure.scan autoheader aclocal.m4 configure.in config.h.in makefile.am automake configure makefile.in./configure makefile 图 3.9 autotools 生 成 makefile 的 流 程 图 3.6.2 使 用 autotools 所 生 成 的 makefile autotools 生 成 的 makefile 除 具 有 普 通 的 编 译 功 能 外, 还 具 有 以 下 主 要 功 能 ( 感 兴 趣 的 读 者 可 以 查 看 这 个 简 单 的 hello.c 程 序 的 makefile)

1.make 键 入 make 默 认 执 行 make all 命 令, 即 目 标 体 为 all, 其 执 行 情 况 如 下 所 示 : [root@localhost automake]# make if gcc -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"hello\" -DVERSION=\"1.0\" -I. -I. -g -O2 -MT hello.o -MD -MP -MF ".deps/hello.tpo" -c -o hello.o hello.c; \ then mv -f ".deps/hello.tpo" ".deps/hello.po"; else rm -f ".deps/hello.tpo"; exit 1; fi gcc -g -O2 -o hello hello.o 此 时 在 本 目 录 下 就 生 成 了 可 执 行 文 件 hello, 运 行./hello 能 出 现 正 常 结 果, 如 下 所 示 : [root@localhost automake]#./hello Hello!Autoconf! 2.make install 此 时, 会 把 该 程 序 安 装 到 系 统 目 录 中 去, 如 下 所 示 : [root@localhost automake]# make install if gcc -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"hello\" -DVERSION=\"1.0\" -I. -I. -g -O2 -MT hello.o -MD -MP -MF ".deps/hello.tpo" -c -o hello.o hello.c; \ then mv -f ".deps/hello.tpo" ".deps/hello.po"; else rm -f ".deps/hello.tpo"; exit 1; fi gcc -g -O2 -o hello hello.o make[1]: Entering directory '/root/workplace/automake' test -z "/usr/local/bin" mkdir -p -- "/usr/local/bin" /usr/bin/install -c 'hello' '/usr/local/bin/hello' make[1]: Nothing to be done for 'install-data-am'. make[1]: Leaving directory '/root/workplace/automake' 此 时, 若 直 接 运 行 hello, 也 能 出 现 正 确 结 果, 如 下 所 示 : [root@localhost automake]# hello Hello!Autoconf! 3.make clean 此 时,make 会 清 除 之 前 所 编 译 的 可 执 行 文 件 及 目 标 文 件 (object file, *.o), 如 下