Microsoft Word - 嵌入式&C.doc.doc



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

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

<433A5C446F63756D656E E E67735C41646D696E F725CD7C0C3E65CC2DBCEC4CFB5CDB3CAB9D3C3D6B8C4CFA3A8BCF2BBAFA3A95CCAB9D3C3D6B8C4CF31302D31392E646F63>

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

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

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

I

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

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

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


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

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

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

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

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

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


<4D F736F F D D323630D6D0B9FAD3A6B6D4C6F8BAF2B1E4BBAFB5C4D5FEB2DFD3EBD0D0B6AF C4EAB6C8B1A8B8E6>

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

修改版-操作手册.doc

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

国债回购交易业务指引

 编号:

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


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

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

<433A5C C6B73625C B746F705CB9FABCCAD6D0D2BDD2A9D7A8D2B5B8DFBCB6BCBCCAF5D6B0B3C6C6C0C9F3C9EAC7EBD6B8C4CFA3A CDA8D3C3B0E6A3A92E646F63>

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

Template BR_Rec_2005.dot

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

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

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

珠江钢琴股东大会

第二讲 数列

课程类 别

Microsoft Word - 文件汇编.doc

<4D F736F F D20B9D8D3DAB0BABBAAA3A8C9CFBAA3A3A9D7D4B6AFBBAFB9A4B3CCB9C9B7DDD3D0CFDEB9ABCBBE C4EAC4EAB6C8B9C9B6ABB4F3BBE1B7A8C2C9D2E2BCFBCAE92E646F6378>

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

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

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

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


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

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

2014年中央财经大学研究生招生录取工作简报


¹ º ¹ º 农 业 流 动 人 口 是 指 户 口 性 质 为 农 业 户 口 在 流 入 地 城 市 工 作 生 活 居 住 一 个 月 及 以 上 的 流 动 人 口 非 农 流 动 人 口 是 指 户 口 性 质 为 非 农 户 口 在 流 入 地 城 市 工 作 生 活 居 住 一 个

一、资质申请

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

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

中 中 中 中 部 中 岗 位 条 件 历 其 它 历 史 师 地 理 师 生 物 师 体 与 健 康 师 从 事 中 历 史 工 从 事 中 地 理 工 从 事 中 生 物 工 从 事 中 体 与 健 康 工 2. 课 程 与 论 ( 历 史 ); 2. 科 ( 历 史 )

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

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

中 国 软 科 学 年 第 期!!!

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

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

<4D F736F F D C4EAB9A4B3CCCBB6CABFCAFDD1A7D7A8D2B5BFCEBFBCCAD4B4F3B8D9D3EBD2AAC7F3>

证券代码: 证券简称:长城电脑 公告编号:

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


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

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

上海证券交易所会议纪要

Microsoft Word - 第3章.doc

现 场 会 议 时 间 为 :2016 年 5 月 19 日 网 络 投 票 时 间 为 :2016 年 5 月 18 日 年 5 月 19 日 其 中 通 过 深 圳 证 券 交 易 所 交 易 系 统 进 行 网 络 投 票 的 时 间 为 2016 年 5 月 19 日 9:30-

untitled

21 业 余 制 -- 高 起 专 (12 级 ) 75 元 / 学 分 网 络 学 院 学 生 沪 教 委 财 (2005)49 号 江 西 化 校 工 科 22 业 余 制 -- 高 起 专 (12 级 ) 70 元 / 学 分 网 络 学 院 学 生 沪 教 委 财 (2005)49 号 吉

教师上报成绩流程图

GONGZUO JUJIAO 宝 山 区 领 军 人 才 名 单 宝 山 区 第 七 批 拔 尖 人 才 名 单 2

新, 各 地 各 部 门 ( 单 位 ) 各 文 化 事 业 单 位 要 高 度 重 视, 切 实 加 强 领 导, 精 心 组 织 实 施 要 根 据 事 业 单 位 岗 位 设 置 管 理 的 规 定 和 要 求, 在 深 入 调 查 研 究 广 泛 听 取 意 见 的 基 础 上, 研 究 提

学 年 第 二 学 期 集 中 考 试 安 排 (18 周 ) 考 试 日 期 :6 月 27 日 星 期 一 8:10-9:50 第 二 公 共 教 学 楼 A 区 A 高 等 数 学 ( 理 二 2) 复 材 材 料 科 学 与 工 程

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

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

<4D F736F F D20BFC9B1E0B3CCD0F2BFD8D6C6CFB5CDB3C9E8BCC6CAA6B9FABCD2D6B0D2B5B1EAD7BC2E646F63>

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

·岗位设置管理流程

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

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

国家职业标准:网络课件设计师

年 8 月 11 日, 公 司 召 开 2015 年 第 五 次 临 时 股 东 大 会, 审 议 通 过 了 关 于 公 司 <2015 年 股 票 期 权 激 励 计 划 ( 草 案 )> 及 其 摘 要 的 议 案 关 于 提 请 股 东 大 会 授 权 董 事 会 办 理 公


公 开 刊 物 须 有 国 内 统 一 刊 (CN), 发 表 文 章 的 刊 物 需 要 在 国 家 新 闻 出 版 广 电 总 局 ( 办 事 服 务 便 民 查 询 新 闻 出 版 机 构 查 询 ) 上 能 够 查 到 刊 凡 在 有 中 国 标 准 书 公 开

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

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

年 第 期 % %! & % % % % % % &

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

2 根 据 广 东 省 交 通 建 设 工 程 施 工 现 场 开 工 前 考 核 评 表 或 根 据 广 东 省 交 通 建 设 工 程 施 工 现 场 实 施 过 程 考 核 评 表 的 和 内 容 进 行 核 查 ; 3 现 场 抽 查 具 有 代 表 性 的 各 岗 位 人 员 ( 从 事

2. 本 次 修 改 后, 投 资 者 申 购 新 股 的 持 有 市 值 要 求 市 值 计 算 规 则 及 证 券 账 户 使 用 的 相 关 规 定 是 否 发 生 了 变 化? 答 : 未 发 生 变 化 投 资 者 申 购 新 股 的 持 有 市 值 是 指, 以 投 资 者 为 单 位

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

光明乳业股份有限公司

第1篇 道路桥梁工程技术核心专业课程标准及学习绩效考评体系

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

<4D F736F F D C3E6CFF2B6D4CFF3A3A8B5DAC8FDD5C220C0E0CCD8D0D4A3A92E646F63>

股票代码:000936

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


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

( 此 页 无 正 文, 为 广 东 东 方 精 工 科 技 股 份 有 限 公 司 关 于 提 供 资 料 真 实 准 确 和 完 整 的 承 诺 函 之 签 署 页 ) 广 东 东 方 精 工 科 技 股 份 有 限 公 司 法 定 代 表 人 : 唐 灼 林 2016 年 7 月 28 日

Transcription:

嵌 入 式 C/C++ 语 言 精 华 文 章 集 锦 C/C+ 语 言 struct 深 层 探 索...2 C++ 中 extern "C" 含 义 深 层 探 索...7 C 语 言 高 效 编 程 的 几 招...11 想 成 为 嵌 入 式 程 序 员 应 知 道 的 0x10 个 基 本 问 题...15 C 语 言 嵌 入 式 系 统 编 程 修 炼...22 C 语 言 嵌 入 式 系 统 编 程 修 炼 之 一 : 背 景 篇...22 C 语 言 嵌 入 式 系 统 编 程 修 炼 之 二 : 软 件 架 构 篇...24 C 语 言 嵌 入 式 系 统 编 程 修 炼 之 三 : 内 存 操 作...30 C 语 言 嵌 入 式 系 统 编 程 修 炼 之 四 : 屏 幕 操 作...36 C 语 言 嵌 入 式 系 统 编 程 修 炼 之 五 : 键 盘 操 作...43 C 语 言 嵌 入 式 系 统 编 程 修 炼 之 六 : 性 能 优 化...46 C/C++ 语 言 void 及 void 指 针 深 层 探 索...50 C/C++ 语 言 可 变 参 数 表 深 层 探 索...54 C/C++ 数 组 名 与 指 针 区 别 深 层 探 索...60 C/C++ 程 序 员 应 聘 常 见 面 试 题 深 入 剖 析 (1)...62 C/C++ 程 序 员 应 聘 常 见 面 试 题 深 入 剖 析 (2)...67 一 道 著 名 外 企 面 试 题 的 抽 丝 剥 茧...74 C/C++ 结 构 体 的 一 个 高 级 特 性 指 定 成 员 的 位 数...78 C/C++ 中 的 近 指 令 远 指 针 和 巨 指 针...80 从 两 道 经 典 试 题 谈 C/C++ 中 联 合 体 (union) 的 使 用...81 基 于 ARM 的 嵌 入 式 Linux 移 植 真 实 体 验...83 基 于 ARM 的 嵌 入 式 Linux 移 植 真 实 体 验 (1) 基 本 概 念...83 基 于 ARM 的 嵌 入 式 Linux 移 植 真 实 体 验 (2) BootLoader...96 基 于 ARM 的 嵌 入 式 Linux 移 植 真 实 体 验 (3) 操 作 系 统...111 基 于 ARM 的 嵌 入 式 Linux 移 植 真 实 体 验 (4) 设 备 驱 动...120 基 于 ARM 的 嵌 入 式 Linux 移 植 真 实 体 验 (5) 应 用 实 例...135 深 入 浅 出 Linux 设 备 驱 动 编 程...144 1.Linux 内 核 模 块...144 2. 字 符 设 备 驱 动 程 序...146 3. 设 备 驱 动 中 的 并 发 控 制...151 4. 设 备 的 阻 塞 与 非 阻 塞 操 作...157 1

C/C+ 语 言 struct 深 层 探 索 出 处 :PConline 作 者 : 宋 宝 华 1. struct 的 巨 大 作 用 面 对 一 个 人 的 大 型 C/C++ 程 序 时, 只 看 其 对 struct 的 使 用 情 况 我 们 就 可 以 对 其 编 写 者 的 编 程 经 验 进 行 评 估 因 为 一 个 大 型 的 C/C++ 程 序, 势 必 要 涉 及 一 些 ( 甚 至 大 量 ) 进 行 数 据 组 合 的 结 构 体, 这 些 结 构 体 可 以 将 原 本 意 义 属 于 一 个 整 体 的 数 据 组 合 在 一 起 从 某 种 程 度 上 来 说, 会 不 会 用 struct, 怎 样 用 struct 是 区 别 一 个 开 发 人 员 是 否 具 备 丰 富 开 发 经 历 的 标 志 在 网 络 协 议 通 信 控 制 嵌 入 式 系 统 的 C/C++ 编 程 中, 我 们 经 常 要 传 送 的 不 是 简 单 的 字 节 流 (char 型 数 组 ), 而 是 多 种 数 据 组 合 起 来 的 一 个 整 体, 其 表 现 形 式 是 一 个 结 构 体 经 验 不 足 的 开 发 人 员 往 往 将 所 有 需 要 传 送 的 内 容 依 顺 序 保 存 在 char 型 数 组 中, 通 过 指 针 偏 移 的 方 法 传 送 网 络 报 文 等 信 息 这 样 做 编 程 复 杂, 易 出 错, 而 且 一 旦 控 制 方 式 及 通 信 协 议 有 所 变 化, 程 序 就 要 进 行 非 常 细 致 的 修 改 一 个 有 经 验 的 开 发 者 则 灵 活 运 用 结 构 体, 举 一 个 例 子, 假 设 网 络 或 控 制 协 议 中 需 要 传 送 三 种 报 文, 其 格 式 分 别 为 packeta packetb packetc: struct structa int a; char b; ; struct structb char a; short b; ; struct structc int a; char b; float c; 优 秀 的 程 序 设 计 者 这 样 设 计 传 送 的 报 文 : struct CommuPacket 2

int ipackettype; // 报 文 类 型 标 志 union // 每 次 传 送 的 是 三 种 报 文 中 的 一 种, 使 用 union struct structa packeta; struct structb packetb; struct structc packetc; ; 在 进 行 报 文 传 送 时, 直 接 传 送 struct CommuPacket 一 个 整 体 假 设 发 送 函 数 的 原 形 如 下 : // psenddata: 发 送 字 节 流 的 首 地 址,iLen: 要 发 送 的 长 度 Send(char * psenddata, unsigned int ilen); 发 送 方 可 以 直 接 进 行 如 下 调 用 发 送 struct CommuPacket 的 一 个 实 例 sendcommupacket: Send( (char *)&sendcommupacket, sizeof(commupacket) ); 假 设 接 收 函 数 的 原 形 如 下 : // precvdata: 发 送 字 节 流 的 首 地 址,iLen: 要 接 收 的 长 度 // 返 回 值 : 实 际 接 收 到 的 字 节 数 unsigned int Recv(char * precvdata, unsigned int ilen); 接 收 方 可 以 直 接 进 行 如 下 调 用 将 接 收 到 的 数 据 保 存 在 struct CommuPacket 的 一 个 实 例 recvcommupacket 中 : Recv( (char *)&recvcommupacket, sizeof(commupacket) ); 接 着 判 断 报 文 类 型 进 行 相 应 处 理 : switch(recvcommupacket. ipackettype) case PACKET_A: break; //A 类 报 文 处 理 case PACKET_B: break; //B 类 报 文 处 理 case PACKET_C: break; //C 类 报 文 处 理 以 上 程 序 中 最 值 得 注 意 的 是 Send( (char *)&sendcommupacket, sizeof(commupacket) ); Recv( (char *)&recvcommupacket, sizeof(commupacket) ); 中 的 强 制 类 型 转 换 :(char *)&sendcommupacket (char *)&recvcommupacket, 先 取 地 址, 再 转 化 为 char 型 指 针, 这 样 就 可 以 直 接 利 用 处 理 字 节 流 的 函 数 利 用 这 种 强 制 类 型 转 化, 我 们 还 可 以 方 便 程 序 的 编 写, 例 如 要 对 sendcommupacket 所 处 内 存 初 始 化 为 0, 可 以 这 样 调 用 标 准 库 函 数 memset(): memset((char *)&sendcommupacket,0, sizeof(commupacket)); 2. struct 的 成 员 对 齐 Intel 微 软 等 公 司 曾 经 出 过 一 道 类 似 的 面 试 题 : #include <iostream.h> 3

#pragma pack(8) struct example1 ; short a; long b; struct example2 ; char c; example1 struct1; short e; #pragma pack() int main(int argc, char* argv[]) example2 struct2; cout << sizeof(example1) << endl; cout << sizeof(example2) << endl; cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2) << endl; return 0; 问 程 序 的 输 入 结 果 是 什 么? 答 案 是 : 8 16 4 不 明 白? 还 是 不 明 白? 下 面 一 一 道 来 : 2.1 自 然 对 界 struct 是 一 种 复 合 数 据 类 型, 其 构 成 元 素 既 可 以 是 基 本 数 据 类 型 ( 如 int long float 等 ) 的 变 量, 也 可 以 是 一 些 复 合 数 据 类 型 ( 如 array struct union 等 ) 的 数 据 单 元 对 于 结 构 体, 编 译 器 会 自 动 进 行 成 员 变 量 的 对 齐, 以 提 高 运 算 效 率 缺 省 情 况 下, 编 译 器 为 结 构 体 的 每 个 成 员 按 其 自 然 对 界 (natural alignment) 条 件 分 配 空 间 各 个 成 员 按 照 它 们 被 声 明 的 顺 序 在 内 存 中 顺 序 存 储, 第 一 个 成 员 的 地 址 和 整 个 结 构 的 地 址 相 同 自 然 对 界 (natural alignment) 即 默 认 对 齐 方 式, 是 指 按 结 构 体 的 成 员 中 size 最 大 的 成 员 对 齐 例 如 : struct naturalalign ; char a; short b; char c; 在 上 述 结 构 体 中,size 最 大 的 是 short, 其 长 度 为 2 字 节, 因 而 结 构 体 中 的 char 成 员 a c 都 以 2 为 单 位 对 齐, sizeof(naturalalign) 的 结 果 等 于 6; 如 果 改 为 : struct naturalalign 4

; char a; int b; char c; 其 结 果 显 然 为 12 2.2 指 定 对 界 一 般 地, 可 以 通 过 下 面 的 方 法 来 改 变 缺 省 的 对 界 条 件 : 使 用 伪 指 令 #pragma pack (n), 编 译 器 将 按 照 n 个 字 节 对 齐 ; 使 用 伪 指 令 #pragma pack (), 取 消 自 定 义 字 节 对 齐 方 式 注 意 : 如 果 #pragma pack (n) 中 指 定 的 n 大 于 结 构 体 中 最 大 成 员 的 size, 则 其 不 起 作 用, 结 构 体 仍 然 按 照 size 最 大 的 成 员 进 行 对 界 例 如 : #pragma pack (n) struct naturalalign char a; int b; char c; ; #pragma pack () 当 n 为 4 8 16 时, 其 对 齐 方 式 均 一 样,sizeof(naturalalign) 的 结 果 都 等 于 12 而 当 n 为 2 时, 其 发 挥 了 作 用, 使 得 sizeof(naturalalign) 的 结 果 为 6 在 VC++ 6.0 编 译 器 中, 我 们 可 以 指 定 其 对 界 方 式 ( 见 图 1), 其 操 作 方 式 为 依 次 选 择 projetct > setting > C/C++ 菜 单, 在 struct member alignment 中 指 定 你 要 的 对 界 方 式 图 1 在 VC++ 6.0 中 指 定 对 界 方 式 5

另 外, 通 过 attribute((aligned (n))) 也 可 以 让 所 作 用 的 结 构 体 成 员 对 齐 在 n 字 节 边 界 上, 但 是 它 较 少 被 使 用, 因 而 不 作 详 细 讲 解 2.3 面 试 题 的 解 答 至 此, 我 们 可 以 对 Intel 微 软 的 面 试 题 进 行 全 面 的 解 答 程 序 中 第 2 行 #pragma pack (8) 虽 然 指 定 了 对 界 为 8, 但 是 由 于 struct example1 中 的 成 员 最 大 size 为 4(long 变 量 size 为 4), 故 struct example1 仍 然 按 4 字 节 对 界,struct example1 的 size 为 8, 即 第 18 行 的 输 出 结 果 ; struct example2 中 包 含 了 struct example1, 其 本 身 包 含 的 简 单 数 据 成 员 的 最 大 size 为 2(short 变 量 e), 但 是 因 为 其 包 含 了 struct example1, 而 struct example1 中 的 最 大 成 员 size 为 4,struct example2 也 应 以 4 对 界,#pragma pack (8) 中 指 定 的 对 界 对 struct example2 也 不 起 作 用, 故 19 行 的 输 出 结 果 为 16; 由 于 struct example2 中 的 成 员 以 4 为 单 位 对 界, 故 其 char 变 量 c 后 应 补 充 3 个 空, 其 后 才 是 成 员 struct1 的 内 存 空 间,20 行 的 输 出 结 果 为 4 3. C 和 C++ 间 struct 的 深 层 区 别 在 C++ 语 言 中 struct 具 有 了 类 的 功 能, 其 与 关 键 字 class 的 区 别 在 于 struct 中 成 员 变 量 和 函 数 的 默 认 访 问 权 限 为 public, 而 class 的 为 private 例 如, 定 义 struct 类 和 class 类 : struct structa char a; class classb char a; 则 : structa a; a.a = 'a'; // 访 问 public 成 员, 合 法 classb b; b.a = 'a'; // 访 问 private 成 员, 不 合 法 许 多 文 献 写 到 这 里 就 认 为 已 经 给 出 了 C++ 中 struct 和 class 的 全 部 区 别, 实 则 不 然, 另 外 一 点 需 要 注 意 的 是 : C++ 中 的 struct 保 持 了 对 C 中 struct 的 全 面 兼 容 ( 这 符 合 C++ 的 初 衷 a better c ), 因 而, 下 面 的 操 作 是 合 法 的 : // 定 义 struct struct structa char a; char b; int c; ; 6

structa a = 'a', 'a',1; // 定 义 时 直 接 赋 初 值 即 struct 可 以 在 定 义 的 时 候 直 接 以 对 其 成 员 变 量 赋 初 值, 而 class 则 不 能, 在 经 典 书 目 thinking C++ 2 nd edition 中 作 者 对 此 点 进 行 了 强 调 4. struct 编 程 注 意 事 项 看 看 下 面 的 程 序 : 1. #include <iostream.h> 2. struct structa 3. 4. int imember; 5. char *cmember; 6. ; 7. int main(int argc, char* argv[]) 8. 9. structa instant1,instant2; 10. char c = 'a'; 11. instant1.imember = 1; 12. instant1.cmember = &c; 13. instant2 = instant1; 14. cout << *(instant1.cmember) << endl; 15. *(instant2.cmember) = 'b'; 16. cout << *(instant1.cmember) << endl; 17. return 0; 14 行 的 输 出 结 果 是 :a 16 行 的 输 出 结 果 是 :b Why? 我 们 在 15 行 对 instant2 的 修 改 改 变 了 instant1 中 成 员 的 值! 原 因 在 于 13 行 的 instant2 = instant1 赋 值 语 句 采 用 的 是 变 量 逐 个 拷 贝, 这 使 得 instant1 和 instant2 中 的 cmember 指 向 了 同 一 片 内 存, 因 而 对 instant2 的 修 改 也 是 对 instant1 的 修 改 在 C 语 言 中, 当 结 构 体 中 存 在 指 针 型 成 员 时, 一 定 要 注 意 在 采 用 赋 值 语 句 时 是 否 将 2 个 实 例 中 的 指 针 型 成 员 指 向 了 同 一 片 内 存 在 C++ 语 言 中, 当 结 构 体 中 存 在 指 针 型 成 员 时, 我 们 需 要 重 写 struct 的 拷 贝 构 造 函 数 并 进 行 = 操 作 符 重 载 C++ 中 extern "C" 含 义 深 层 探 索 作 者 : 宋 宝 华 e-mail:21cnbao@21cn.com 出 处 : 太 平 洋 电 脑 网 1. 引 言 C++ 语 言 的 创 建 初 衷 是 a better C, 但 是 这 并 不 意 味 着 C++ 中 类 似 C 语 言 的 全 局 变 量 和 函 数 所 采 用 的 编 译 和 连 接 方 式 与 C 语 言 完 全 相 同 作 为 一 种 欲 与 C 兼 容 的 语 言,C++ 保 留 了 一 部 分 过 程 式 语 言 的 特 点 ( 被 世 人 称 为 不 彻 底 地 面 向 对 象 ), 因 而 它 可 以 定 义 不 属 于 任 何 类 的 全 局 变 量 和 函 数 7

但 是,C++ 毕 竟 是 一 种 面 向 对 象 的 程 序 设 计 语 言, 为 了 支 持 函 数 的 重 载,C++ 对 全 局 函 数 的 处 理 方 式 与 C 有 明 显 的 不 同 2. 从 标 准 头 文 件 说 起 某 企 业 曾 经 给 出 如 下 的 一 道 面 试 题 : 面 试 题 为 什 么 标 准 头 文 件 都 有 类 似 以 下 的 结 构? #ifndef INCvxWorksh #define INCvxWorksh #ifdef cplusplus extern "C" #endif /*...*/ #ifdef cplusplus #endif #endif /* INCvxWorksh */ 分 析 显 然, 头 文 件 中 的 编 译 宏 #ifndef INCvxWorksh #define INCvxWorksh #endif 的 作 用 是 防 止 该 头 文 件 被 重 复 引 用 那 么 #ifdef cplusplus extern "C" #endif #ifdef cplusplus #endif 的 作 用 又 是 什 么 呢? 我 们 将 在 下 文 一 一 道 来 3. 深 层 揭 密 extern "C" extern "C" 包 含 双 重 含 义, 从 字 面 上 即 可 得 到 : 首 先, 被 它 修 饰 的 目 标 是 extern 的 ; 其 次, 被 它 修 饰 的 目 标 是 C 的 让 我 们 来 详 细 解 读 这 两 重 含 义 (1) 被 extern "C" 限 定 的 函 数 或 变 量 是 extern 类 型 的 ; extern 是 C/C++ 语 言 中 表 明 函 数 和 全 局 变 量 作 用 范 围 ( 可 见 性 ) 的 关 键 字, 该 关 键 字 告 诉 编 译 器, 其 声 明 的 函 数 和 变 量 可 以 在 本 模 块 或 其 它 模 块 中 使 用 记 住, 下 列 语 句 : extern int a; 仅 仅 是 一 个 变 量 的 声 明, 其 并 不 是 在 定 义 变 量 a, 并 未 为 a 分 配 内 存 空 间 变 量 a 在 所 有 模 块 中 作 为 一 种 全 局 变 量 只 能 被 定 义 一 次, 否 则 会 出 现 连 接 错 误 通 常, 在 模 块 的 头 文 件 中 对 本 模 块 提 供 给 其 它 模 块 引 用 的 函 数 和 全 局 变 量 以 关 键 字 extern 声 明 例 如, 如 果 模 块 B 欲 引 用 该 模 块 A 中 定 义 的 全 局 变 量 和 函 数 时 只 需 包 含 模 块 A 的 头 文 件 即 可 这 样, 模 块 B 中 调 用 模 块 A 中 的 函 数 时, 在 编 译 阶 段, 模 块 B 虽 然 找 不 到 该 函 数, 但 是 并 不 会 报 错 ; 它 会 在 连 接 阶 段 中 从 模 块 A 编 译 生 成 的 目 标 代 码 中 找 到 此 函 数 与 extern 对 应 的 关 键 字 是 static, 被 它 修 饰 的 全 局 变 量 和 函 数 只 能 在 本 模 块 中 使 用 因 此, 一 个 函 数 或 变 量 只 可 能 被 本 模 块 使 用 时, 其 不 可 能 被 extern C 修 饰 (2) 被 extern "C" 修 饰 的 变 量 和 函 数 是 按 照 C 语 言 方 式 编 译 和 连 接 的 ; 未 加 extern C 声 明 时 的 编 译 方 式 8

首 先 看 看 C++ 中 对 类 似 C 的 函 数 是 怎 样 编 译 的 作 为 一 种 面 向 对 象 的 语 言,C++ 支 持 函 数 重 载, 而 过 程 式 语 言 C 则 不 支 持 函 数 被 C++ 编 译 后 在 符 号 库 中 的 名 字 与 C 语 言 的 不 同 例 如, 假 设 某 个 函 数 的 原 型 为 : void foo( int x, int y ); 该 函 数 被 C 编 译 器 编 译 后 在 符 号 库 中 的 名 字 为 _foo, 而 C++ 编 译 器 则 会 产 生 像 _foo_int_int 之 类 的 名 字 ( 不 同 的 编 译 器 可 能 生 成 的 名 字 不 同, 但 是 都 采 用 了 相 同 的 机 制, 生 成 的 新 名 字 称 为 mangled name ) _foo_int_int 这 样 的 名 字 包 含 了 函 数 名 函 数 参 数 数 量 及 类 型 信 息,C++ 就 是 靠 这 种 机 制 来 实 现 函 数 重 载 的 例 如, 在 C++ 中, 函 数 void foo( int x, int y ) 与 void foo( int x, float y ) 编 译 生 成 的 符 号 是 不 相 同 的, 后 者 为 _foo_int_float 同 样 地,C++ 中 的 变 量 除 支 持 局 部 变 量 外, 还 支 持 类 成 员 变 量 和 全 局 变 量 用 户 所 编 写 程 序 的 类 成 员 变 量 可 能 与 全 局 变 量 同 名, 我 们 以 "." 来 区 分 而 本 质 上, 编 译 器 在 进 行 编 译 时, 与 函 数 的 处 理 相 似, 也 为 类 中 的 变 量 取 了 一 个 独 一 无 二 的 名 字, 这 个 名 字 与 用 户 程 序 中 同 名 的 全 局 变 量 名 字 不 同 未 加 extern "C" 声 明 时 的 连 接 方 式 假 设 在 C++ 中, 模 块 A 的 头 文 件 如 下 : // 模 块 A 头 文 件 modulea.h #ifndef MODULE_A_H #define MODULE_A_H int foo( int x, int y ); #endif 在 模 块 B 中 引 用 该 函 数 : // 模 块 B 实 现 文 件 moduleb.cpp #include "modulea.h" foo(2,3); 实 际 上, 在 连 接 阶 段, 连 接 器 会 从 模 块 A 生 成 的 目 标 文 件 modulea.obj 中 寻 找 _foo_int_int 这 样 的 符 号! 加 extern "C" 声 明 后 的 编 译 和 连 接 方 式 加 extern "C" 声 明 后, 模 块 A 的 头 文 件 变 为 : // 模 块 A 头 文 件 modulea.h #ifndef MODULE_A_H #define MODULE_A_H extern "C" int foo( int x, int y ); #endif 在 模 块 B 的 实 现 文 件 中 仍 然 调 用 foo( 2,3 ), 其 结 果 是 : (1) 模 块 A 编 译 生 成 foo 的 目 标 代 码 时, 没 有 对 其 名 字 进 行 特 殊 处 理, 采 用 了 C 语 言 的 方 式 ; (2) 连 接 器 在 为 模 块 B 的 目 标 代 码 寻 找 foo(2,3) 调 用 时, 寻 找 的 是 未 经 修 改 的 符 号 名 _foo 如 果 在 模 块 A 中 函 数 声 明 了 foo 为 extern "C" 类 型, 而 模 块 B 中 包 含 的 是 extern int foo( int x, int y ), 则 模 块 B 找 不 到 模 块 A 中 的 函 数 ; 反 之 亦 然 所 以, 可 以 用 一 句 话 概 括 extern C 这 个 声 明 的 真 实 目 的 ( 任 何 语 言 中 的 任 何 语 法 特 性 的 诞 生 都 不 是 随 意 而 为 的, 来 源 于 真 实 世 界 的 需 求 驱 动 我 们 在 思 考 问 题 时, 不 能 只 停 留 在 这 个 语 言 是 怎 么 做 的, 还 要 问 一 问 它 为 什 么 要 这 么 做, 动 机 是 什 么, 这 样 我 们 可 以 更 深 入 地 理 解 许 多 问 题 ): 实 现 C++ 与 C 及 其 它 语 言 的 混 合 编 程 明 白 了 C++ 中 extern "C" 的 设 立 动 机, 我 们 下 面 来 具 体 分 析 extern "C" 通 常 的 使 用 技 巧 4.extern "C" 的 惯 用 法 9

(1) 在 C++ 中 引 用 C 语 言 中 的 函 数 和 变 量, 在 包 含 C 语 言 头 文 件 ( 假 设 为 cexample.h) 时, 需 进 行 下 列 处 理 : extern "C" #include "cexample.h" 而 在 C 语 言 的 头 文 件 中, 对 其 外 部 函 数 只 能 指 定 为 extern 类 型,C 语 言 中 不 支 持 extern "C" 声 明, 在.c 文 件 中 包 含 了 extern "C" 时 会 出 现 编 译 语 法 错 误 笔 者 编 写 的 C++ 引 用 C 函 数 例 子 工 程 中 包 含 的 三 个 文 件 的 源 代 码 如 下 : /* c 语 言 头 文 件 :cexample.h */ #ifndef C_EXAMPLE_H #define C_EXAMPLE_H extern int add(int x,int y); #endif /* c 语 言 实 现 文 件 :cexample.c */ #include "cexample.h" int add( int x, int y ) return x + y; // c++ 实 现 文 件, 调 用 add:cppfile.cpp extern "C" #include "cexample.h" int main(int argc, char* argv[]) add(2,3); return 0; 如 果 C++ 调 用 一 个 C 语 言 编 写 的.DLL 时, 当 包 括.DLL 的 头 文 件 或 声 明 接 口 函 数 时, 应 加 extern "C" (2) 在 C 中 引 用 C++ 语 言 中 的 函 数 和 变 量 时,C++ 的 头 文 件 需 添 加 extern "C", 但 是 在 C 语 言 中 不 能 直 接 引 用 声 明 了 extern "C" 的 该 头 文 件, 应 该 仅 将 C 文 件 中 将 C++ 中 定 义 的 extern "C" 函 数 声 明 为 extern 类 型 笔 者 编 写 的 C 引 用 C++ 函 数 例 子 工 程 中 包 含 的 三 个 文 件 的 源 代 码 如 下 : //C++ 头 文 件 cppexample.h #ifndef CPP_EXAMPLE_H #define CPP_EXAMPLE_H extern "C" int add( int x, int y ); #endif //C++ 实 现 文 件 cppexample.cpp #include "cppexample.h" int add( int x, int y ) 10

return x + y; /* C 实 现 文 件 cfile.c /* 这 样 会 编 译 出 错 :#include "cexample.h" */ extern int add( int x, int y ); int main( int argc, char* argv[] ) add( 2, 3 ); return 0; 如 果 深 入 理 解 了 第 3 节 中 所 阐 述 的 extern "C" 在 编 译 和 连 接 阶 段 发 挥 的 作 用, 就 能 真 正 理 解 本 节 所 阐 述 的 从 C++ 引 用 C 函 数 和 C 引 用 C++ 函 数 的 惯 用 法 对 第 4 节 给 出 的 示 例 代 码, 需 要 特 别 留 意 各 个 细 节 C 语 言 高 效 编 程 的 几 招 编 写 高 效 简 洁 的 C 语 言 代 码, 是 许 多 软 件 工 程 师 追 求 的 目 标 本 文 就 工 作 中 的 一 些 体 会 和 经 验 做 相 关 的 阐 述, 不 对 的 地 方 请 各 位 指 教 第 1 招 : 以 空 间 换 时 间 计 算 机 程 序 中 最 大 的 矛 盾 是 空 间 和 时 间 的 矛 盾, 那 么, 从 这 个 角 度 出 发 逆 向 思 维 来 考 虑 程 序 的 效 率 问 题, 我 们 就 有 了 解 决 问 题 的 第 1 招 -- 以 空 间 换 时 间 例 如 : 字 符 串 的 赋 值 方 法 A, 通 常 的 办 法 : #define LEN 32 char string1 [LEN]; memset (string1,0,len); strcpy (string1,"this is an example!!" 方 法 B: const char string2[len]="this is an example!" char*cp; cp=string2; ( 使 用 的 时 候 可 以 直 接 用 指 针 来 操 作 ) 从 上 面 的 例 子 可 以 看 出,A 和 B 的 效 率 是 不 能 比 的 在 同 样 的 存 储 空 间 下,B 直 接 使 用 指 针 就 可 以 操 作 了, 而 A 需 要 调 用 两 个 字 符 函 数 才 能 完 成 B 的 缺 点 在 于 灵 活 性 没 有 A 好 在 需 要 频 繁 更 改 一 个 字 符 串 内 容 的 时 候,A 具 有 更 好 的 灵 活 性 ; 如 果 采 用 方 法 B, 则 需 要 预 存 许 多 字 符 串, 虽 然 占 用 了 大 量 的 内 存, 但 是 获 得 了 程 序 执 行 的 高 效 率 如 果 系 统 的 实 时 性 要 求 很 高, 内 存 还 有 一 些, 那 我 推 荐 你 使 用 该 招 数 11

该 招 数 的 边 招 -- 使 用 宏 函 数 而 不 是 函 数 举 例 如 下 : 方 法 C: #define bwmcdr2_address 4 #define bsmcdr2_address 17 int BIT_MASK (int_bf) return ((IU<<(bw##_bf))-1)<<(bs##_bf); void SET_BITS(int_dst,int_bf,int_val) _dst=((_dst) & ~ (BIT_MASK(_bf)))I\ (((_val)<<<(bs##_bf))&(bit_mask(_bf))) 方 法 D: #define bwmcdr2_address 4 #define bsmcdr2_address 17 #define bmmcdr2_address BIT_MASK (MCDR2_ADDRESS) #define BIT_MASK(_bf)(((1U<<(bw##_bf))-1)<< (bs##_bf) #define SET_BITS(_dst,_bf,_val)\ ((_dst)=((_dst)&~(bit_mask(_bf)))i (((_val)<<(bs##_bf))&(bit_mask(_bf)))) SET_BITS(MCDR2,MCDR2_ADDRESS,RegisterNumb er); SET_BITS(MCDR2,MCDR2_ADDRESS,RegisterNumb er); 函 数 和 宏 函 数 的 区 别 就 在 于, 宏 函 数 占 用 了 大 量 的 空 间, 而 函 数 占 用 了 时 间 大 家 要 知 道 的 是, 函 数 调 用 是 要 使 用 系 统 的 栈 来 保 存 数 据 的, 如 果 编 译 器 里 有 栈 检 查 选 项, 一 般 在 函 数 的 头 会 嵌 入 一 些 汇 编 语 句 对 当 前 栈 进 行 检 查 ; 同 时,CPU 也 要 在 函 数 调 用 时 保 存 和 恢 复 当 前 的 现 场, 进 行 压 栈 和 弹 栈 操 作, 所 以, 函 数 调 用 需 要 一 些 CPU 时 间 而 宏 函 数 不 存 在 这 个 问 题 宏 函 数 仅 仅 作 为 预 先 写 好 的 代 码 嵌 入 到 当 前 程 序, 不 会 产 生 函 数 调 用, 所 以 仅 仅 是 占 用 了 空 间, 在 频 繁 调 用 同 一 个 宏 函 数 的 时 候, 该 现 象 尤 其 突 出 D 方 法 是 我 看 到 的 最 好 的 置 位 操 作 函 数, 是 ARM 公 司 源 码 的 一 部 分, 在 短 短 的 三 行 内 实 现 了 很 多 功 能, 几 乎 涵 盖 了 所 有 的 位 操 作 功 能 C 方 法 是 其 变 体, 其 中 滋 味 还 需 大 家 仔 细 体 会 第 2 招 : 数 学 方 法 解 决 问 题 现 在 我 们 演 绎 高 效 C 语 言 编 写 的 第 二 招 -- 采 用 数 学 方 法 来 解 决 问 题 数 学 是 计 算 机 之 母, 没 有 数 学 的 依 据 和 基 础, 就 没 有 计 算 机 的 发 展, 所 以 在 编 写 程 序 的 时 候, 采 用 一 些 数 学 方 法 会 对 程 序 的 执 行 效 率 有 数 量 级 的 提 高 举 例 如 下, 求 1~100 的 和 方 法 E int I,j; 方 法 F int I; 12

for (I=1; I<=100; I++) I=(100*(1+100))/2 j+=i; 这 个 例 子 是 我 印 象 最 深 的 一 个 数 学 用 例, 是 我 的 饿 计 算 机 启 蒙 老 师 考 我 的 当 时 我 只 有 小 学 三 年 级, 可 惜 我 当 时 不 知 道 用 公 式 Nx(N+1)/2 来 解 决 这 个 问 题 方 法 E 循 环 了 100 次 才 解 决 问 题, 也 就 是 说 最 少 用 了 100 个 赋 值 100 个 判 断 200 个 加 法 (I 和 j); 而 方 法 F 仅 仅 用 了 1 个 加 法 1 个 乘 法 1 次 除 法 效 果 自 然 不 言 而 喻 所 以, 现 在 我 在 编 程 序 的 时 候, 更 多 的 是 动 脑 筋 找 规 律, 最 大 限 度 地 发 挥 数 学 的 威 力 来 提 高 程 序 运 行 的 效 率 第 3 招 : 使 用 位 操 作 实 现 高 效 的 C 语 言 编 写 的 第 三 招 -- 使 用 位 操 作, 减 少 除 法 和 取 模 的 运 算 在 计 算 机 程 序 中, 数 据 的 位 是 可 以 操 作 的 最 小 数 据 单 位, 理 论 上 可 以 用 位 运 算 来 完 成 所 有 的 运 算 和 操 作 一 般 的 位 操 作 是 用 来 控 制 硬 件 的, 或 者 做 数 据 变 换 使 用, 但 是, 灵 活 的 位 操 作 可 以 有 效 地 提 高 程 序 运 行 的 效 率 举 例 台 如 下 : 方 法 G int I,J; I=257/8; J=456%32; 方 法 H int I,J; I=257>>3; J=456-(456>>4<<4); 在 字 面 上 好 象 H 比 G 麻 烦 了 好 多, 但 是, 仔 细 查 看 产 生 的 汇 编 代 码 就 会 明 白, 方 法 G 调 用 了 基 本 的 取 模 函 数 和 除 法 函 数, 既 有 函 数 调 用, 还 有 很 多 汇 编 代 码 和 寄 存 器 参 与 运 算 ; 而 方 法 H 则 仅 仅 是 几 句 相 关 的 汇 编, 代 码 更 简 洁 效 率 更 高 当 然, 由 于 编 译 器 的 不 同, 可 能 效 率 的 差 距 不 大, 但 是, 以 我 目 前 遇 到 的 MS C,ARM C 来 看, 效 率 的 差 距 还 是 不 小 相 关 汇 编 代 码 就 不 在 这 里 列 举 了 运 用 这 招 需 要 注 意 的 是, 因 为 CPU 的 不 同 而 产 生 的 问 题 比 如 说, 在 PC 上 用 这 招 编 写 的 程 序, 并 在 PC 上 调 试 通 过, 在 移 植 到 一 个 16 位 机 平 台 上 的 时 候, 可 能 会 产 生 代 码 隐 患 所 以 只 有 在 一 定 技 术 进 阶 的 基 础 下 才 可 以 使 用 这 招 第 4 招 : 汇 编 嵌 入 高 效 C 语 言 编 程 的 必 杀 技, 第 四 招 -- 嵌 入 汇 编 在 熟 悉 汇 编 语 言 的 人 眼 里,C 语 言 编 写 的 程 序 都 是 垃 圾 这 种 说 法 虽 然 偏 激 了 一 些, 但 是 却 有 它 的 道 理 汇 编 语 言 是 效 率 最 高 的 计 算 机 语 言, 但 是, 不 可 能 靠 着 它 来 写 一 个 操 作 系 统 吧? 所 以, 为 了 获 得 程 序 的 高 效 率, 我 们 只 好 采 用 变 通 的 方 法 -- 嵌 入 汇 编 混 合 编 程 举 例 如 下, 将 数 组 一 赋 值 给 数 组 二, 要 求 每 一 个 字 节 都 相 符 char string1[1024], string2[1024]; 13

方 法 J #int I; for(i=0; I<1024; I++) *(string2+i)=*(string1+i); #else #ifdef_arm asm 方 法 I int I; for (I=0; I<1024; I++) *(string2+i)=*(string1+i) MOV R0,string1 MOV R1,string2 MOV R2,#0 loop: LDMIA R0!,[R3-R11] STMIA R1!,[R3-R11] ADD R2,R2,#8 CMP R2, #400 BNE loop #endif 方 法 I 是 最 常 见 的 方 法, 使 用 了 1024 次 循 环 ; 方 法 J 则 根 据 平 台 不 同 做 了 区 分, 在 ARM 平 台 下, 用 嵌 入 汇 编 仅 用 128 次 循 环 就 完 成 了 同 样 的 操 作 这 里 有 朋 友 会 说, 为 什 么 不 用 标 准 的 内 存 拷 贝 函 数 呢? 这 是 因 为 在 源 数 据 里 可 能 含 有 数 据 为 0 的 字 节, 这 样 的 话, 标 准 库 函 数 会 提 前 结 束 而 不 会 完 成 我 们 要 求 的 操 作 这 个 例 程 典 型 应 用 于 LCD 数 据 的 拷 贝 过 程 根 据 不 同 的 CPU, 熟 练 使 用 相 应 的 嵌 入 汇 编, 可 以 大 大 提 高 程 序 执 行 的 效 率 虽 然 是 必 杀 技, 但 是 如 果 轻 易 使 用 会 付 出 惨 重 的 代 价 这 是 因 为, 使 用 了 嵌 入 汇 编, 便 限 制 了 程 序 的 可 移 植 性, 使 程 序 在 不 同 平 台 移 植 的 过 程 中, 卧 虎 藏 龙 险 象 环 生! 同 时 该 招 数 也 与 现 代 软 件 工 程 的 思 想 相 违 背, 只 有 在 迫 不 得 已 的 情 况 下 才 可 以 采 用 切 记 使 用 C 语 言 进 行 高 效 率 编 程, 我 的 体 会 仅 此 而 已 在 此 已 本 文 抛 砖 引 玉, 还 请 各 位 高 手 共 同 切 磋 希 望 各 位 能 给 出 更 好 的 方 法, 大 家 一 起 提 高 我 们 的 编 程 技 巧 摘 自 单 片 机 与 嵌 入 式 系 统 应 用 2003.9 14

想 成 为 嵌 入 式 程 序 员 应 知 道 的 0x10 个 基 本 问 题 - endeaver 发 表 于 2006-3-8 16:16:00 C 语 言 测 试 是 招 聘 嵌 入 式 系 统 程 序 员 过 程 中 必 须 而 且 有 效 的 方 法 这 些 年, 我 既 参 加 也 组 织 了 许 多 这 种 测 试, 在 这 过 程 中 我 意 识 到 这 些 测 试 能 为 带 面 试 者 和 被 面 试 者 提 供 许 多 有 用 信 息, 此 外, 撇 开 面 试 的 压 力 不 谈, 这 种 测 试 也 是 相 当 有 趣 的 从 被 面 试 者 的 角 度 来 讲, 你 能 了 解 许 多 关 于 出 题 者 或 监 考 者 的 情 况 这 个 测 试 只 是 出 题 者 为 显 示 其 对 ANSI 标 准 细 节 的 知 识 而 不 是 技 术 技 巧 而 设 计 吗? 这 个 愚 蠢 的 问 题 吗? 如 要 你 答 出 某 个 字 符 的 ASCII 值 这 些 问 题 着 重 考 察 你 的 系 统 调 用 和 内 存 分 配 策 略 方 面 的 能 力 吗? 这 标 志 着 出 题 者 也 许 花 时 间 在 微 机 上 而 不 上 在 嵌 入 式 系 统 上 如 果 上 述 任 何 问 题 的 答 案 是 " 是 " 的 话, 那 么 我 知 道 我 得 认 真 考 虑 我 是 否 应 该 去 做 这 份 工 作 从 面 试 者 的 角 度 来 讲, 一 个 测 试 也 许 能 从 多 方 面 揭 示 应 试 者 的 素 质 : 最 基 本 的, 你 能 了 解 应 试 者 C 语 言 的 水 平 不 管 怎 么 样, 看 一 下 这 人 如 何 回 答 他 不 会 的 问 题 也 是 满 有 趣 应 试 者 是 以 好 的 直 觉 做 出 明 智 的 选 择, 还 是 只 是 瞎 蒙 呢? 当 应 试 者 在 某 个 问 题 上 卡 住 时 是 找 借 口 呢, 还 是 表 现 出 对 问 题 的 真 正 的 好 奇 心, 把 这 看 成 学 习 的 机 会 呢? 我 发 现 这 些 信 息 与 他 们 的 测 试 成 绩 一 样 有 用 有 了 这 些 想 法, 我 决 定 出 一 些 真 正 针 对 嵌 入 式 系 统 的 考 题, 希 望 这 些 令 人 头 痛 的 考 题 能 给 正 在 找 工 作 的 人 一 点 帮 住 这 些 问 题 都 是 我 这 些 年 实 际 碰 到 的 其 中 有 些 题 很 难, 但 它 们 应 该 都 能 给 你 一 点 启 迪 这 个 测 试 适 于 不 同 水 平 的 应 试 者, 大 多 数 初 级 水 平 的 应 试 者 的 成 绩 会 很 差, 经 验 丰 富 的 程 序 员 应 该 有 很 好 的 成 绩 为 了 让 你 能 自 己 决 定 某 些 问 题 的 偏 好, 每 个 问 题 没 有 分 配 分 数, 如 果 选 择 这 些 考 题 为 你 所 用, 请 自 行 按 你 的 意 思 分 配 分 数 预 处 理 器 (Preprocessor) 1. 用 预 处 理 指 令 #define 声 明 一 个 常 数, 用 以 表 明 1 年 中 有 多 少 秒 ( 忽 略 闰 年 问 题 ) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我 在 这 想 看 到 几 件 事 情 : ; #define 语 法 的 基 本 知 识 ( 例 如 : 不 能 以 分 号 结 束, 括 号 的 使 用, 等 等 ) ; 懂 得 预 处 理 器 将 为 你 计 算 常 数 表 达 式 的 值, 因 此, 直 接 写 出 你 是 如 何 计 算 一 年 中 有 多 少 秒 而 不 是 计 算 出 实 际 的 值, 是 更 清 晰 而 没 有 代 价 的 ; 意 识 到 这 个 表 达 式 将 使 一 个 16 位 机 的 整 型 数 溢 出 - 因 此 要 用 到 长 整 型 符 号 L, 告 诉 编 译 器 这 个 常 数 是 的 长 整 型 数 ; 如 果 你 在 你 的 表 达 式 中 用 到 UL( 表 示 无 符 号 长 整 型 ), 那 么 你 有 了 一 个 好 的 起 点 记 住, 第 一 印 象 很 重 要 2. 写 一 个 " 标 准 " 宏 MIN, 这 个 宏 输 入 两 个 参 数 并 返 回 较 小 的 一 个 #define MIN(A,B) ((A) <= (B)? (A) : (B)) 这 个 测 试 是 为 下 面 的 目 的 而 设 的 : ; 标 识 #define 在 宏 中 应 用 的 基 本 知 识 这 是 很 重 要 的, 因 为 直 到 嵌 入 (inline) 操 作 符 变 为 标 准 C 的 一 部 分, 宏 是 方 便 产 生 嵌 入 代 码 的 唯 一 方 法, 对 于 嵌 入 式 系 统 来 说, 为 了 能 达 到 要 求 的 性 能, 嵌 入 代 码 经 常 是 必 须 的 方 法 ; 三 重 条 件 操 作 符 的 知 识 这 个 操 作 符 存 在 C 语 言 中 的 原 因 是 它 使 得 编 译 器 能 产 生 比 if-then-else 更 优 化 的 代 码, 了 解 这 个 用 法 是 很 重 要 的 ; 懂 得 在 宏 中 小 心 地 把 参 数 用 括 号 括 起 来 ; 我 也 用 这 个 问 题 开 始 讨 论 宏 的 副 作 用, 例 如 : 当 你 写 下 面 的 代 码 时 会 发 生 什 么 事? least = MIN(*p++, b); 3. 预 处 理 器 标 识 #error 的 目 的 是 什 么? 如 果 你 不 知 道 答 案, 请 看 参 考 文 献 1 这 问 题 对 区 分 一 个 正 常 的 伙 计 和 一 个 书 呆 子 是 很 有 用 的 只 有 书 呆 子 才 会 读 C 语 言 课 本 的 附 录 去 找 出 象 这 种 问 题 的 答 案 当 然 如 果 你 不 是 在 找 一 个 书 呆 子, 那 么 应 试 者 最 好 希 望 自 己 不 要 知 道 答 案 死 循 环 (Infinite loops) 4. 嵌 入 式 系 统 中 经 常 要 用 到 无 限 循 环, 你 怎 么 样 用 C 编 写 死 循 环 呢? 15

这 个 问 题 用 几 个 解 决 方 案 我 首 选 的 方 案 是 : while(1)? 一 些 程 序 员 更 喜 欢 如 下 方 案 : for(;;)? 这 个 实 现 方 式 让 我 为 难, 因 为 这 个 语 法 没 有 确 切 表 达 到 底 怎 么 回 事 如 果 一 个 应 试 者 给 出 这 个 作 为 方 案, 我 将 用 这 个 作 为 一 个 机 会 去 探 究 他 们 这 样 做 的 基 本 原 理 如 果 他 们 的 基 本 答 案 是 :" 我 被 教 着 这 样 做, 但 从 没 有 想 到 过 为 什 么 " 这 会 给 我 留 下 一 个 坏 印 象 第 三 个 方 案 是 用 goto Loop:... goto Loop; 应 试 者 如 给 出 上 面 的 方 案, 这 说 明 或 者 他 是 一 个 汇 编 语 言 程 序 员 ( 这 也 许 是 好 事 ) 或 者 他 是 一 个 想 进 入 新 领 域 的 BASIC/FORTRAN 程 序 员 数 据 声 明 (Data declarations) 5. 用 变 量 a 给 出 下 面 的 定 义 a) 一 个 整 型 数 (An integer) b) 一 个 指 向 整 型 数 的 指 针 ( A pointer to an integer) c) 一 个 指 向 指 针 的 的 指 针, 它 指 向 的 指 针 是 指 向 一 个 整 型 数 ( A pointer to a pointer to an intege)r d) 一 个 有 10 个 整 型 数 的 数 组 ( An array of 10 integers) e) 一 个 有 10 个 指 针 的 数 组, 该 指 针 是 指 向 一 个 整 型 数 的 (An array of 10 pointers to integers) f) 一 个 指 向 有 10 个 整 型 数 数 组 的 指 针 ( A pointer to an array of 10 integers) g) 一 个 指 向 函 数 的 指 针, 该 函 数 有 一 个 整 型 参 数 并 返 回 一 个 整 型 数 (A pointer to a function that takes an integer as an argument and returns an integer) h) 一 个 有 10 个 指 针 的 数 组, 该 指 针 指 向 一 个 函 数, 该 函 数 有 一 个 整 型 参 数 并 返 回 一 个 整 型 数 ( An array of ten pointers to functions t hat take an integer argument and return an integer ) 答 案 是 : a) int a; // An integer b) int *a; // A pointer to an integer c) int **a; // A pointer to a pointer to an integer d) int a[10]; // An array of 10 integers e) int *a[10]; // An array of 10 pointers to integers f) int (*a)[10]; // A pointer to an array of 10 integers g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer 人 们 经 常 声 称 这 里 有 几 个 问 题 是 那 种 要 翻 一 下 书 才 能 回 答 的 问 题, 我 同 意 这 种 说 法 当 我 写 这 篇 文 章 时, 为 了 确 定 语 法 的 正 确 性, 我 的 确 查 了 一 下 书 但 是 当 我 被 面 试 的 时 候, 我 期 望 被 问 到 这 个 问 题 ( 或 者 相 近 的 问 题 ) 因 为 在 被 面 试 的 这 段 时 间 里, 我 确 定 我 知 道 这 个 问 题 的 答 案 应 试 者 如 果 不 知 道 所 有 的 答 案 ( 或 至 少 大 部 分 答 案 ), 那 么 也 就 没 有 为 这 次 面 试 做 准 备, 如 果 该 面 试 者 没 有 为 这 次 面 试 做 准 备, 那 么 他 又 能 为 什 么 出 准 备 呢? 16

Static 6. 关 键 字 static 的 作 用 是 什 么? 这 个 简 单 的 问 题 很 少 有 人 能 回 答 完 全 在 C 语 言 中, 关 键 字 static 有 三 个 明 显 的 作 用 : ; 在 函 数 体, 一 个 被 声 明 为 静 态 的 变 量 在 这 一 函 数 被 调 用 过 程 中 维 持 其 值 不 变 ; 在 模 块 内 ( 但 在 函 数 体 外 ), 一 个 被 声 明 为 静 态 的 变 量 可 以 被 模 块 内 所 用 函 数 访 问, 但 不 能 被 模 块 外 其 它 函 数 访 问 它 是 一 个 本 地 的 全 局 变 量 ; 在 模 块 内, 一 个 被 声 明 为 静 态 的 函 数 只 可 被 这 一 模 块 内 的 其 它 函 数 调 用 那 就 是, 这 个 函 数 被 限 制 在 声 明 它 的 模 块 的 本 地 范 围 内 使 用 大 多 数 应 试 者 能 正 确 回 答 第 一 部 分, 一 部 分 能 正 确 回 答 第 二 部 分, 同 是 很 少 的 人 能 懂 得 第 三 部 分 这 是 一 个 应 试 者 的 严 重 的 缺 点, 因 为 他 显 然 不 懂 得 本 地 化 数 据 和 代 码 范 围 的 好 处 和 重 要 性 Const 7. 关 键 字 const 有 什 么 含 意? 我 只 要 一 听 到 被 面 试 者 说 :"const 意 味 着 常 数 ", 我 就 知 道 我 正 在 和 一 个 业 余 者 打 交 道 去 年 Dan Saks 已 经 在 他 的 文 章 里 完 全 概 括 了 const 的 所 有 用 法, 因 此 ESP( 译 者 :Embedded Systems Programming) 的 每 一 位 读 者 应 该 非 常 熟 悉 const 能 做 什 么 和 不 能 做 什 么. 如 果 你 从 没 有 读 到 那 篇 文 章, 只 要 能 说 出 const 意 味 着 " 只 读 " 就 可 以 了 尽 管 这 个 答 案 不 是 完 全 的 答 案, 但 我 接 受 它 作 为 一 个 正 确 的 答 案 ( 如 果 你 想 知 道 更 详 细 的 答 案, 仔 细 读 一 下 Saks 的 文 章 吧 ) 如 果 应 试 者 能 正 确 回 答 这 个 问 题, 我 将 问 他 一 个 附 加 的 问 题 : 下 面 的 声 明 都 是 什 么 意 思? const int a; int const a; const int *a; int * const a; int const * a const; /******/ 前 两 个 的 作 用 是 一 样,a 是 一 个 常 整 型 数 第 三 个 意 味 着 a 是 一 个 指 向 常 整 型 数 的 指 针 ( 也 就 是, 整 型 数 是 不 可 修 改 的, 但 指 针 可 以 ) 第 四 个 意 思 a 是 一 个 指 向 整 型 数 的 常 指 针 ( 也 就 是 说, 指 针 指 向 的 整 型 数 是 可 以 修 改 的, 但 指 针 是 不 可 修 改 的 ) 最 后 一 个 意 味 着 a 是 一 个 指 向 常 整 型 数 的 常 指 针 ( 也 就 是 说, 指 针 指 向 的 整 型 数 是 不 可 修 改 的, 同 时 指 针 也 是 不 可 修 改 的 ) 如 果 应 试 者 能 正 确 回 答 这 些 问 题, 那 么 他 就 给 我 留 下 了 一 个 好 印 象 顺 带 提 一 句, 也 许 你 可 能 会 问, 即 使 不 用 关 键 字 const, 也 还 是 能 很 容 易 写 出 功 能 正 确 的 程 序, 那 么 我 为 什 么 还 要 如 此 看 重 关 键 字 const 呢? 我 也 如 下 的 几 下 理 由 : ; 关 键 字 const 的 作 用 是 为 给 读 你 代 码 的 人 传 达 非 常 有 用 的 信 息, 实 际 上, 声 明 一 个 参 数 为 常 量 是 为 了 告 诉 了 用 户 这 个 参 数 的 应 用 目 的 如 果 你 曾 花 很 多 时 间 清 理 其 它 人 留 下 的 垃 圾, 你 就 会 很 快 学 会 感 谢 这 点 多 余 的 信 息 ( 当 然, 懂 得 用 const 的 程 序 员 很 少 会 留 下 的 垃 圾 让 别 人 来 清 理 的 ) ; 通 过 给 优 化 器 一 些 附 加 的 信 息, 使 用 关 键 字 const 也 许 能 产 生 更 紧 凑 的 代 码 ; 合 理 地 使 用 关 键 字 const 可 以 使 编 译 器 很 自 然 地 保 护 那 些 不 希 望 被 改 变 的 参 数, 防 止 其 被 无 意 的 代 码 修 改 简 而 言 之, 这 样 可 以 减 少 bug 的 出 现 Volatile 8. 关 键 字 volatile 有 什 么 含 意? 并 给 出 三 个 不 同 的 例 子 一 个 定 义 为 volatile 的 变 量 是 说 这 变 量 可 能 会 被 意 想 不 到 地 改 变, 这 样, 编 译 器 就 不 会 去 假 设 这 个 变 量 的 值 了 精 确 地 说 就 是, 优 化 器 在 用 到 这 个 变 量 时 必 须 每 次 都 小 心 地 重 新 读 取 这 个 变 量 的 值, 而 不 是 使 用 保 存 在 寄 存 器 里 的 备 份 下 面 是 volatile 变 量 的 几 个 例 子 : 17

; 并 行 设 备 的 硬 件 寄 存 器 ( 如 : 状 态 寄 存 器 ) ; 一 个 中 断 服 务 子 程 序 中 会 访 问 到 的 非 自 动 变 量 (Non-automatic variables) ; 多 线 程 应 用 中 被 几 个 任 务 共 享 的 变 量 回 答 不 出 这 个 问 题 的 人 是 不 会 被 雇 佣 的 我 认 为 这 是 区 分 C 程 序 员 和 嵌 入 式 系 统 程 序 员 的 最 基 本 的 问 题 搞 嵌 入 式 的 家 伙 们 经 常 同 硬 件 中 断 RTOS 等 等 打 交 道, 所 有 这 些 都 要 求 用 到 volatile 变 量 不 懂 得 volatile 的 内 容 将 会 带 来 灾 难 假 设 被 面 试 者 正 确 地 回 答 了 这 是 问 题 ( 嗯, 怀 疑 是 否 会 是 这 样 ), 我 将 稍 微 深 究 一 下, 看 一 下 这 家 伙 是 不 是 直 正 懂 得 volatile 完 全 的 重 要 性 ; 一 个 参 数 既 可 以 是 const 还 可 以 是 volatile 吗? 解 释 为 什 么 ; 一 个 指 针 可 以 是 volatile 吗? 解 释 为 什 么 ; 下 面 的 函 数 有 什 么 错 误 : int square(volatile int *ptr) return *ptr * *ptr; 下 面 是 答 案 : ; 是 的 一 个 例 子 是 只 读 的 状 态 寄 存 器 它 是 volatile 因 为 它 可 能 被 意 想 不 到 地 改 变 它 是 const 因 为 程 序 不 应 该 试 图 去 修 改 它 ; 是 的 尽 管 这 并 不 很 常 见 一 个 例 子 是 当 一 个 中 服 务 子 程 序 修 该 一 个 指 向 一 个 buffer 的 指 针 时 ; 这 段 代 码 有 点 变 态 这 段 代 码 的 目 的 是 用 来 返 指 针 *ptr 指 向 值 的 平 方, 但 是, 由 于 *ptr 指 向 一 个 volatile 型 参 数, 编 译 器 将 产 生 类 似 下 面 的 代 码 : int square(volatile int *ptr) int a,b; a = *ptr; b = *ptr; return a * b; 由 于 *ptr 的 值 可 能 被 意 想 不 到 地 该 变, 因 此 a 和 b 可 能 是 不 同 的 结 果, 这 段 代 码 可 能 返 不 是 你 所 期 望 的 平 方 值! 正 确 的 代 码 如 下 : long square(volatile int *ptr) int a; a = *ptr; return a * a; 位 操 作 (Bit manipulation) 9. 嵌 入 式 系 统 总 是 要 用 户 对 变 量 或 寄 存 器 进 行 位 操 作 给 定 一 个 整 型 变 量 a, 写 两 段 代 码, 第 一 个 设 置 a 的 bit 3, 第 二 个 清 除 a 的 bit 3 在 以 上 两 个 操 作 中, 要 保 持 其 它 位 不 变 18

对 这 个 问 题 有 三 种 基 本 的 反 应 ; 不 知 道 如 何 下 手 该 被 面 者 从 没 做 过 任 何 嵌 入 式 系 统 的 工 作 ; 用 bit fields Bit fields 是 被 扔 到 C 语 言 死 角 的 东 西, 它 保 证 你 的 代 码 在 不 同 编 译 器 之 间 是 不 可 移 植 的, 同 时 也 保 证 了 的 你 的 代 码 是 不 可 重 用 的 我 最 近 不 幸 看 到 Infineon 为 其 较 复 杂 的 通 信 芯 片 写 的 驱 动 程 序, 它 用 到 了 bit fields 因 此 完 全 对 我 无 用, 因 为 我 的 编 译 器 用 其 它 的 方 式 来 实 现 bit fields 的 从 道 德 讲 : 永 远 不 要 让 一 个 非 嵌 入 式 的 家 伙 粘 实 际 硬 件 的 边 ; 用 #defines 和 bit masks 操 作 这 是 一 个 有 极 高 可 移 植 性 的 方 法, 是 应 该 被 用 到 的 方 法 最 佳 的 解 决 方 案 如 下 : #define BIT3 (0x1 << 3) static int a; void set_bit3(void) a = BIT3; void clear_bit3(void) a &= ~BIT3; 一 些 人 喜 欢 为 设 置 和 清 除 值 而 定 义 一 个 掩 码 同 时 定 义 一 些 说 明 常 数, 这 也 是 可 以 接 受 的 我 希 望 看 到 几 个 要 点 : 说 明 常 数 = 和 &=~ 操 作 访 问 固 定 的 内 存 位 置 (Accessing fixed memory locations) 10. 嵌 入 式 系 统 经 常 具 有 要 求 程 序 员 去 访 问 某 特 定 的 内 存 位 置 的 特 点 在 某 工 程 中, 要 求 设 置 一 绝 对 地 址 为 0x67a9 的 整 型 变 量 的 值 为 0xaa6 6 编 译 器 是 一 个 纯 粹 的 ANSI 编 译 器 写 代 码 去 完 成 这 一 任 务 这 一 问 题 测 试 你 是 否 知 道 为 了 访 问 一 绝 对 地 址 把 一 个 整 型 数 强 制 转 换 (typecast) 为 一 指 针 是 合 法 的 这 一 问 题 的 实 现 方 式 随 着 个 人 风 格 不 同 而 不 同 典 型 的 类 似 代 码 如 下 : int *ptr; ptr = (int *)0x67a9; *ptr = 0xaa55; A more obscure approach is: 一 个 较 晦 涩 的 方 法 是 : *(int * const)(0x67a9) = 0xaa55; 即 使 你 的 品 味 更 接 近 第 二 种 方 案, 但 我 建 议 你 在 面 试 时 使 用 第 一 种 方 案 中 断 (Interrupts) 11. 中 断 是 嵌 入 式 系 统 中 重 要 的 组 成 部 分, 这 导 致 了 很 多 编 译 开 发 商 提 供 一 种 扩 展 让 标 准 C 支 持 中 断 具 代 表 事 实 是, 产 生 了 一 个 新 的 关 键 字 interrupt 下 面 的 代 码 就 使 用 了 interrupt 关 键 字 去 定 义 了 一 个 中 断 服 务 子 程 序 (ISR), 请 评 论 一 下 这 段 代 码 的 interrupt double compute_area (double radius) 19

double area = PI * radius * radius; printf("\narea = %f", area); return area; 这 个 函 数 有 太 多 的 错 误 了, 以 至 让 人 不 知 从 何 说 起 了 : ; ISR 不 能 返 回 一 个 值 如 果 你 不 懂 这 个, 那 么 你 不 会 被 雇 用 的 ; ISR 不 能 传 递 参 数 如 果 你 没 有 看 到 这 一 点, 你 被 雇 用 的 机 会 等 同 第 一 项 ; 在 许 多 的 处 理 器 / 编 译 器 中, 浮 点 一 般 都 是 不 可 重 入 的 有 些 处 理 器 / 编 译 器 需 要 让 额 处 的 寄 存 器 入 栈, 有 些 处 理 器 / 编 译 器 就 是 不 允 许 在 IS R 中 做 浮 点 运 算 此 外,ISR 应 该 是 短 而 有 效 率 的, 在 ISR 中 做 浮 点 运 算 是 不 明 智 的 ; 与 第 三 点 一 脉 相 承,printf() 经 常 有 重 入 和 性 能 上 的 问 题 如 果 你 丢 掉 了 第 三 和 第 四 点, 我 不 会 太 为 难 你 的 不 用 说, 如 果 你 能 得 到 后 两 点, 那 么 你 的 被 雇 用 前 景 越 来 越 光 明 了 ***** 代 码 例 子 (Code examples) 12. 下 面 的 代 码 输 出 是 什 么, 为 什 么? void foo(void) unsigned int a = 6; int b = -20; (a+b > 6)? puts("> 6") : puts("<= 6"); 这 个 问 题 测 试 你 是 否 懂 得 C 语 言 中 的 整 数 自 动 转 换 原 则, 我 发 现 有 些 开 发 者 懂 得 极 少 这 些 东 西 不 管 如 何, 这 无 符 号 整 型 问 题 的 答 案 是 输 出 是 ">6" 原 因 是 当 表 达 式 中 存 在 有 符 号 类 型 和 无 符 号 类 型 时 所 有 的 操 作 数 都 自 动 转 换 为 无 符 号 类 型 因 此 -20 变 成 了 一 个 非 常 大 的 正 整 数, 所 以 该 表 达 式 计 算 出 的 结 果 大 于 6 这 一 点 对 于 应 当 频 繁 用 到 无 符 号 数 据 类 型 的 嵌 入 式 系 统 来 说 是 丰 常 重 要 的 如 果 你 答 错 了 这 个 问 题, 你 也 就 到 了 得 不 到 这 份 工 作 的 边 缘 13. 评 价 下 面 的 代 码 片 断 : unsigned int zero = 0; unsigned int compzero = 0xFFFF; /*1's complement of zero */ 对 于 一 个 int 型 不 是 16 位 的 处 理 器 为 说, 上 面 的 代 码 是 不 正 确 的 应 编 写 如 下 : unsigned int compzero = ~0; 这 一 问 题 真 正 能 揭 露 出 应 试 者 是 否 懂 得 处 理 器 字 长 的 重 要 性 在 我 的 经 验 里, 好 的 嵌 入 式 程 序 员 非 常 准 确 地 明 白 硬 件 的 细 节 和 它 的 局 限, 然 而 P C 机 程 序 往 往 把 硬 件 作 为 一 个 无 法 避 免 的 烦 恼 到 了 这 个 阶 段, 应 试 者 或 者 完 全 垂 头 丧 气 了 或 者 信 心 满 满 志 在 必 得 如 果 显 然 应 试 者 不 是 很 好, 那 么 这 个 测 试 就 在 这 里 结 束 了 但 如 果 显 然 应 试 者 做 得 不 错, 那 么 我 就 扔 出 下 面 的 追 加 问 题, 这 些 问 题 是 比 较 难 的, 我 想 仅 仅 非 常 优 秀 的 应 试 者 能 做 得 不 错 提 出 这 些 问 题, 我 希 望 更 多 看 到 应 试 者 应 付 问 题 的 方 法, 而 不 是 答 案 不 管 如 何, 你 就 当 是 这 个 娱 乐 吧... 20

动 态 内 存 分 配 (Dynamic memory allocation) 14. 尽 管 不 像 非 嵌 入 式 计 算 机 那 么 常 见, 嵌 入 式 系 统 还 是 有 从 堆 (heap) 中 动 态 分 配 内 存 的 过 程 的 那 么 嵌 入 式 系 统 中, 动 态 分 配 内 存 可 能 发 生 的 问 题 是 什 么? 这 里, 我 期 望 应 试 者 能 提 到 内 存 碎 片, 碎 片 收 集 的 问 题, 变 量 的 持 行 时 间 等 等 这 个 主 题 已 经 在 ESP 杂 志 中 被 广 泛 地 讨 论 过 了 ( 主 要 是 P.J. Plauger, 他 的 解 释 远 远 超 过 我 这 里 能 提 到 的 任 何 解 释 ), 所 有 回 过 头 看 一 下 这 些 杂 志 吧! 让 应 试 者 进 入 一 种 虚 假 的 安 全 感 觉 后, 我 拿 出 这 么 一 个 小 节 目 : 下 面 的 代 码 片 段 的 输 出 是 什 么, 为 什 么? char *ptr; if ((ptr = (char *)malloc(0)) == NULL) else puts("got a null pointer"); puts("got a valid pointer"); 这 是 一 个 有 趣 的 问 题 最 近 在 我 的 一 个 同 事 不 经 意 把 0 值 传 给 了 函 数 malloc, 得 到 了 一 个 合 法 的 指 针 之 后, 我 才 想 到 这 个 问 题 这 就 是 上 面 的 代 码, 该 代 码 的 输 出 是 "Got a valid pointer" 我 用 这 个 来 开 始 讨 论 这 样 的 一 问 题, 看 看 被 面 试 者 是 否 想 到 库 例 程 这 样 做 是 正 确 得 到 正 确 的 答 案 固 然 重 要, 但 解 决 问 题 的 方 法 和 你 做 决 定 的 基 本 原 理 更 重 要 些 Typedef : 15 Typedef 在 C 语 言 中 频 繁 用 以 声 明 一 个 已 经 存 在 的 数 据 类 型 的 同 义 字 也 可 以 用 预 处 理 器 做 类 似 的 事 例 如, 思 考 一 下 下 面 的 例 子 : #define dps struct s * typedef struct s * tps; 以 上 两 种 情 况 的 意 图 都 是 要 定 义 dps 和 tps 作 为 一 个 指 向 结 构 s 指 针 哪 种 方 法 更 好 呢?( 如 果 有 的 话 ) 为 什 么? 这 是 一 个 非 常 微 妙 的 问 题, 任 何 人 答 对 这 个 问 题 ( 正 当 的 原 因 ) 是 应 当 被 恭 喜 的 答 案 是 :typedef 更 好 思 考 下 面 的 例 子 : dps p1,p2; tps p3,p4; 第 一 个 扩 展 为 struct s * p1, p2;. 上 面 的 代 码 定 义 p1 为 一 个 指 向 结 构 的 指,p2 为 一 个 实 际 的 结 构, 这 也 许 不 是 你 想 要 的 第 二 个 例 子 正 确 地 定 义 了 p3 和 p4 两 个 指 针 晦 涩 的 语 法 16. C 语 言 同 意 一 些 令 人 震 惊 的 结 构, 下 面 的 结 构 是 合 法 的 吗, 如 果 是 它 做 些 什 么? int a = 5, b = 7, c; c = a+++b; 21

这 个 问 题 将 做 为 这 个 测 验 的 一 个 愉 快 的 结 尾 不 管 你 相 不 相 信, 上 面 的 例 子 是 完 全 合 乎 语 法 的 问 题 是 编 译 器 如 何 处 理 它? 水 平 不 高 的 编 译 作 者 实 际 上 会 争 论 这 个 问 题, 根 据 最 处 理 原 则, 编 译 器 应 当 能 处 理 尽 可 能 所 有 合 法 的 用 法 因 此, 上 面 的 代 码 被 处 理 成 : c = a++ + b; 因 此, 这 段 代 码 持 行 后 a = 6, b = 7, c = 12 如 果 你 知 道 答 案, 或 猜 出 正 确 答 案, 做 得 好 如 果 你 不 知 道 答 案, 我 也 不 把 这 个 当 作 问 题 我 发 现 这 个 问 题 的 最 大 好 处 是 这 是 一 个 关 于 代 码 编 写 风 格, 代 码 的 可 读 性, 代 码 的 可 修 改 性 的 好 的 话 题 好 了, 伙 计 们, 你 现 在 已 经 做 完 所 有 的 测 试 了 这 就 是 我 出 的 C 语 言 测 试 题, 我 怀 着 愉 快 的 心 情 写 完 它, 希 望 你 以 同 样 的 心 情 读 完 它 如 果 是 认 为 这 是 一 个 好 的 测 试, 那 么 尽 量 都 用 到 你 的 找 工 作 的 过 程 中 去 吧 天 知 道 也 许 过 个 一 两 年, 我 就 不 做 现 在 的 工 作, 也 需 要 找 一 个 Nigel Jones 是 一 个 顾 问, 现 在 住 在 Maryland, 当 他 不 在 水 下 时, 你 能 在 多 个 范 围 的 嵌 入 项 目 中 找 到 他 他 很 高 兴 能 收 到 读 者 的 来 信, 他 的 email 地 址 是 : NAJones@compuserve.com References ; Jones, Nigel, "In Praise of the #error directive," Embedded Systems Programming, September 1999, p. 114. ; Jones, Nigel, " Efficient C Code for Eight-bit MCUs," Embedded Systems Programming, November 1998, p. 66 C 语 言 嵌 入 式 系 统 编 程 修 炼 C 语 言 嵌 入 式 系 统 编 程 修 炼 之 一 : 背 景 篇 作 者 : 宋 宝 华 更 新 日 期 :2005-08-30 来 源 :yesky.com 不 同 于 一 般 形 式 的 软 件 编 程, 嵌 入 式 系 统 编 程 建 立 在 特 定 的 硬 件 平 台 上, 势 必 要 求 其 编 程 语 言 具 备 较 强 的 硬 件 直 接 操 作 能 力 无 疑, 汇 编 语 言 具 备 这 样 的 特 质 但 是, 归 因 于 汇 编 语 言 开 发 过 程 的 复 杂 性, 它 并 不 是 嵌 入 式 系 统 开 发 的 一 般 选 择 而 与 之 相 比,C 语 言 -- 一 种 " 高 级 的 低 级 " 语 言, 则 成 为 嵌 入 式 系 统 开 发 的 最 佳 选 择 笔 者 在 嵌 入 式 系 统 项 目 的 开 发 过 程 中, 一 次 又 一 次 感 受 到 C 语 言 的 精 妙, 沉 醉 于 C 语 言 给 嵌 入 式 开 发 带 来 的 便 利 图 1 给 出 了 本 文 的 讨 论 所 基 于 的 硬 件 平 台, 实 际 上, 这 也 是 大 多 数 嵌 入 式 系 统 的 硬 件 平 台 它 包 括 两 部 分 : (1) 以 通 用 处 理 器 为 中 心 的 协 议 处 理 模 块, 用 于 网 络 控 制 协 议 的 处 理 ; (2) 以 数 字 信 号 处 理 器 (DSP) 为 中 心 的 信 号 处 理 模 块, 用 于 调 制 解 调 和 数 / 模 信 号 转 换 本 文 的 讨 论 主 要 围 绕 以 通 用 处 理 器 为 中 心 的 协 议 处 理 模 块 进 行, 因 为 它 更 多 地 牵 涉 到 具 体 的 C 语 言 编 程 技 巧 而 DSP 编 程 则 重 点 关 注 具 体 的 数 字 信 号 处 理 算 法, 主 要 涉 及 通 信 领 域 的 知 识, 不 是 本 文 的 讨 论 重 点 22

着 眼 于 讨 论 普 遍 的 嵌 入 式 系 统 C 编 程 技 巧, 系 统 的 协 议 处 理 模 块 没 有 选 择 特 别 的 CPU, 而 是 选 择 了 众 所 周 知 的 CPU 芯 片 --80186, 每 一 位 学 习 过 微 机 原 理 的 读 者 都 应 该 对 此 芯 片 有 一 个 基 本 的 认 识, 且 对 其 指 令 集 比 较 熟 悉 80186 的 字 长 是 16 位, 可 以 寻 址 到 的 内 存 空 间 为 1MB, 只 有 实 地 址 模 式 C 语 言 编 译 生 成 的 指 针 为 32 位 ( 双 字 ), 高 16 位 为 段 地 址, 低 16 位 为 段 内 偏 移, 一 段 最 多 64KB 图 1 系 统 硬 件 架 构 协 议 处 理 模 块 中 的 FLASH 和 RAM 几 乎 是 每 个 嵌 入 式 系 统 的 必 备 设 备, 前 者 用 于 存 储 程 序, 后 者 则 是 程 序 运 行 时 指 令 及 数 据 的 存 放 位 置 系 统 所 选 择 的 FLASH 和 RAM 的 位 宽 都 为 16 位, 与 CPU 一 致 实 时 钟 芯 片 可 以 为 系 统 定 时, 给 出 当 前 的 年 月 日 及 具 体 时 间 ( 小 时 分 秒 及 毫 秒 ), 可 以 设 定 其 经 过 一 段 时 间 即 向 CPU 提 出 中 断 或 设 定 报 警 时 间 到 来 时 向 CPU 提 出 中 断 ( 类 似 闹 钟 功 能 ) NVRAM( 非 易 失 去 性 RAM) 具 有 掉 电 不 丢 失 数 据 的 特 性, 可 以 用 于 保 存 系 统 的 设 置 信 息, 譬 如 网 络 协 议 参 数 等 在 系 统 掉 电 或 重 新 启 动 后, 仍 然 可 以 读 取 先 前 的 设 置 信 息 其 位 宽 为 8 位, 比 CPU 字 长 小 文 章 特 意 选 择 一 个 与 CPU 字 长 不 一 致 的 存 储 芯 片, 为 后 文 中 一 节 的 讨 论 创 造 条 件 UART 则 完 成 CPU 并 行 数 据 传 输 与 RS-232 串 行 数 据 传 输 的 转 换, 它 可 以 在 接 收 到 [1~MAX_BUFFER] 字 节 后 向 CPU 提 出 中 断,MAX_BUFFER 为 UART 芯 片 存 储 接 收 到 字 节 的 最 大 缓 冲 区 键 盘 控 制 器 和 显 示 控 制 器 则 完 成 系 统 人 机 界 面 的 控 制 以 上 提 供 的 是 一 个 较 完 备 的 嵌 入 式 系 统 硬 件 架 构, 实 际 的 系 统 可 能 包 含 更 少 的 外 设 之 所 以 选 择 一 个 完 备 的 系 统, 是 为 了 后 文 更 全 面 的 讨 论 嵌 入 式 系 统 C 语 言 编 程 技 巧 的 方 方 面 面, 所 有 设 备 都 会 成 为 后 文 的 分 析 目 标 嵌 入 式 系 统 需 要 良 好 的 软 件 开 发 环 境 的 支 持, 由 于 嵌 入 式 系 统 的 目 标 机 资 源 受 限, 不 可 能 在 其 上 建 立 庞 大 复 杂 的 开 发 环 境, 因 而 其 开 发 环 境 和 目 标 运 行 环 境 相 互 分 离 因 此, 嵌 入 式 应 用 软 件 的 开 发 方 式 一 般 是, 在 宿 主 机 (Host) 上 建 立 开 发 环 境, 进 行 应 用 程 序 编 码 和 交 叉 编 译, 然 后 宿 主 机 同 目 标 机 (Target) 建 立 连 接, 将 应 用 程 序 下 载 到 目 标 机 上 进 行 交 叉 调 试, 经 过 调 试 和 优 化, 最 后 将 应 用 程 序 固 化 到 目 标 机 中 实 际 运 行 CAD-UL 是 适 用 于 x86 处 理 器 的 嵌 入 式 应 用 软 件 开 发 环 境, 它 运 行 在 Windows 操 作 系 统 之 上, 可 生 成 x86 处 理 器 的 目 标 23

代 码 并 通 过 PC 机 的 COM 口 (RS-232 串 口 ) 或 以 太 网 口 下 载 到 目 标 机 上 运 行, 如 图 2 其 驻 留 于 目 标 机 FLASH 存 储 器 中 的 monitor 程 序 可 以 监 控 宿 主 机 Windows 调 试 平 台 上 的 用 户 调 试 指 令, 获 取 CPU 寄 存 器 的 值 及 目 标 机 存 储 空 间 I/O 空 间 的 内 容 图 2 交 叉 开 发 环 境 后 续 章 节 将 从 软 件 架 构 内 存 操 作 屏 幕 操 作 键 盘 操 作 性 能 优 化 等 多 方 面 阐 述 C 语 言 嵌 入 式 系 统 的 编 程 技 巧 软 件 架 构 是 一 个 宏 观 概 念, 与 具 体 硬 件 的 联 系 不 大 ; 内 存 操 作 主 要 涉 及 系 统 中 的 FLASH RAM 和 NVRAM 芯 片 ; 屏 幕 操 作 则 涉 及 显 示 控 制 器 和 实 时 钟 ; 键 盘 操 作 主 要 涉 及 键 盘 控 制 器 ; 性 能 优 化 则 给 出 一 些 具 体 的 减 小 程 序 时 间 空 间 消 耗 的 技 巧 在 我 们 的 修 炼 旅 途 中 将 经 过 25 个 关 口, 这 些 关 口 主 分 为 两 类, 一 类 是 技 巧 型, 有 很 强 的 适 用 性 ; 一 类 则 是 常 识 型, 在 理 论 上 有 些 意 义 C 语 言 嵌 入 式 系 统 编 程 修 炼 之 二 : 软 件 架 构 篇 作 者 : 宋 宝 华 更 新 日 期 :2005-07-22 模 块 划 分 模 块 划 分 的 " 划 " 是 规 划 的 意 思, 意 指 怎 样 合 理 的 将 一 个 很 大 的 软 件 划 分 为 一 系 列 功 能 独 立 的 部 分 合 作 完 成 系 统 的 需 求 C 语 言 作 为 一 种 结 构 化 的 程 序 设 计 语 言, 在 模 块 的 划 分 上 主 要 依 据 功 能 ( 依 功 能 进 行 划 分 在 面 向 对 象 设 计 中 成 为 一 个 错 误, 牛 顿 定 律 遇 到 了 > 相 对 论 ),C 语 言 模 块 化 程 序 设 计 需 理 解 如 下 概 念 : (1) 模 块 即 是 一 个.c 文 件 和 一 个.h 文 件 的 结 合, 头 文 件 (.h) 中 是 对 于 该 模 块 接 口 的 声 明 ; (2) 某 模 块 提 供 给 其 它 模 块 调 用 的 外 部 函 数 及 数 据 需 在.h 中 文 件 中 冠 以 extern 关 键 字 声 明 ; (3) 模 块 内 的 函 数 和 全 局 变 量 需 在.c 文 件 开 头 冠 以 static 关 键 字 声 明 ; (4) 永 远 不 要 在.h 文 件 中 定 义 变 量! 定 义 变 量 和 声 明 变 量 的 区 别 在 于 定 义 会 产 生 内 存 分 配 的 操 作, 是 汇 编 阶 段 的 概 念 ; 而 声 明 则 只 是 告 诉 包 含 该 声 明 的 模 块 在 连 接 阶 段 从 其 它 模 块 寻 找 外 部 函 数 和 变 量 如 : /*module1.h*/ int a = 5; /* 在 模 块 1 的.h 文 件 中 定 义 int a */ /*module1.c*/ #include "module1.h" /* 在 模 块 1 中 包 含 模 块 1 的.h 文 件 */ 24

/*module2.c*/ #include "module1.h" /* 在 模 块 2 中 包 含 模 块 1 的.h 文 件 */ /*module3.c*/ #include "module1.h" /* 在 模 块 3 中 包 含 模 块 1 的.h 文 件 */ 以 上 程 序 的 结 果 是 在 模 块 1 2 3 中 都 定 义 了 整 型 变 量 a,a 在 不 同 的 模 块 中 对 应 不 同 的 地 址 单 元, 这 个 世 界 上 从 来 不 需 要 这 样 的 程 序 正 确 的 做 法 是 : /*module1.h*/ extern int a; /* 在 模 块 1 的.h 文 件 中 声 明 int a */ /*module1.c*/ #include "module1.h" /* 在 模 块 1 中 包 含 模 块 1 的.h 文 件 */ int a = 5; /* 在 模 块 1 的.c 文 件 中 定 义 int a */ /*module2.c*/ #include "module1.h" /* 在 模 块 2 中 包 含 模 块 1 的.h 文 件 */ /*module3.c*/ #include "module1.h" /* 在 模 块 3 中 包 含 模 块 1 的.h 文 件 */ 这 样 如 果 模 块 1 2 3 操 作 a 的 话, 对 应 的 是 同 一 片 内 存 单 元 一 个 嵌 入 式 系 统 通 常 包 括 两 类 模 块 : (1) 硬 件 驱 动 模 块, 一 种 特 定 硬 件 对 应 一 个 模 块 ; (2) 软 件 功 能 模 块, 其 模 块 的 划 分 应 满 足 低 偶 合 高 内 聚 的 要 求 多 任 务 还 是 单 任 务 所 谓 " 单 任 务 系 统 " 是 指 该 系 统 不 能 支 持 多 任 务 并 发 操 作, 宏 观 串 行 地 执 行 一 个 任 务 而 多 任 务 系 统 则 可 以 宏 观 并 行 ( 微 观 上 可 能 串 行 ) 地 " 同 时 " 执 行 多 个 任 务 多 任 务 的 并 发 执 行 通 常 依 赖 于 一 个 多 任 务 操 作 系 统 (OS), 多 任 务 OS 的 核 心 是 系 统 调 度 器, 它 使 用 任 务 控 制 块 (TCB) 来 管 理 任 务 调 度 功 能 TCB 包 括 任 务 的 当 前 状 态 优 先 级 要 等 待 的 事 件 或 资 源 任 务 程 序 码 的 起 始 地 址 初 始 堆 栈 指 针 等 信 息 调 度 器 在 任 务 被 激 活 时, 要 用 到 这 些 信 息 此 外,TCB 还 被 用 来 存 放 任 务 的 " 上 下 文 "(context) 任 务 的 上 下 文 就 是 当 一 个 执 行 中 的 任 务 被 停 止 时, 所 要 保 存 的 所 有 信 息 通 常, 上 下 文 就 是 计 算 机 当 前 的 状 态, 也 即 各 个 寄 存 器 的 内 容 当 发 生 任 务 切 换 时, 当 前 运 行 的 任 务 的 上 下 文 被 存 入 TCB, 并 将 要 被 执 行 的 任 务 的 上 下 文 从 它 的 TCB 中 取 出, 放 入 各 个 寄 存 器 中 嵌 入 式 多 任 务 OS 的 典 型 例 子 有 Vxworks uclinux 等 嵌 入 式 OS 并 非 遥 不 可 及 的 神 坛 之 物, 我 们 可 以 用 不 到 1000 25

行 代 码 实 现 一 个 针 对 80186 处 理 器 的 功 能 最 简 单 的 OS 内 核, 作 者 正 准 备 进 行 此 项 工 作, 希 望 能 将 心 得 贡 献 给 大 家 究 竟 选 择 多 任 务 还 是 单 任 务 方 式, 依 赖 于 软 件 的 体 系 是 否 庞 大 例 如, 绝 大 多 数 手 机 程 序 都 是 多 任 务 的, 但 也 有 一 些 小 灵 通 的 协 议 栈 是 单 任 务 的, 没 有 操 作 系 统, 它 们 的 主 程 序 轮 流 调 用 各 个 软 件 模 块 的 处 理 程 序, 模 拟 多 任 务 环 境 单 任 务 程 序 典 型 架 构 (1) 从 CPU 复 位 时 的 指 定 地 址 开 始 执 行 ; (2) 跳 转 至 汇 编 代 码 startup 处 执 行 ; (3) 跳 转 至 用 户 主 程 序 main 执 行, 在 main 中 完 成 : a. 初 试 化 各 硬 件 设 备 ; b. 初 始 化 各 软 件 模 块 ; c. 进 入 死 循 环 ( 无 限 循 环 ), 调 用 各 模 块 的 处 理 函 数 用 户 主 程 序 和 各 模 块 的 处 理 函 数 都 以 C 语 言 完 成 用 户 主 程 序 最 后 都 进 入 了 一 个 死 循 环, 其 首 选 方 案 是 : while(1) 有 的 程 序 员 这 样 写 : for(;;) 这 个 语 法 没 有 确 切 表 达 代 码 的 含 义, 我 们 从 for(;;) 看 不 出 什 么, 只 有 弄 明 白 for(;;) 在 C 语 言 中 意 味 着 无 条 件 循 环 才 明 白 其 意 下 面 是 几 个 " 著 名 " 的 死 循 环 : (1) 操 作 系 统 是 死 循 环 ; (2)WIN32 程 序 是 死 循 环 ; (3) 嵌 入 式 系 统 软 件 是 死 循 环 ; (4) 多 线 程 程 序 的 线 程 处 理 函 数 是 死 循 环 你 可 能 会 辩 驳, 大 声 说 :" 凡 事 都 不 是 绝 对 的,2 3 4 都 可 以 不 是 死 循 环 " Yes,you are right, 但 是 你 得 不 到 鲜 26

花 和 掌 声 实 际 上, 这 是 一 个 没 有 太 大 意 义 的 牛 角 尖, 因 为 这 个 世 界 从 来 不 需 要 一 个 处 理 完 几 个 消 息 就 喊 着 要 OS 杀 死 它 的 WIN32 程 序, 不 需 要 一 个 刚 开 始 RUN 就 自 行 了 断 的 嵌 入 式 系 统, 不 需 要 莫 名 其 妙 启 动 一 个 做 一 点 事 就 干 掉 自 己 的 线 程 有 时 候, 过 于 严 谨 制 造 的 不 是 便 利 而 是 麻 烦 君 不 见, 五 层 的 TCP/IP 协 议 栈 超 越 严 谨 的 ISO/OSI 七 层 协 议 栈 大 行 其 道 成 为 事 实 上 的 标 准? 经 常 有 网 友 讨 论 : printf("%d,%d",++i,i++); /* 输 出 是 什 么?*/ c = a+++b; /* c=? */ 等 类 似 问 题 面 对 这 些 问 题, 我 们 只 能 发 出 由 衷 的 感 慨 : 世 界 上 还 有 很 多 有 意 义 的 事 情 等 着 我 们 去 消 化 摄 入 的 食 物 实 际 上, 嵌 入 式 系 统 要 运 行 到 世 界 末 日 中 断 服 务 程 序 中 断 是 嵌 入 式 系 统 中 重 要 的 组 成 部 分, 但 是 在 标 准 C 中 不 包 含 中 断 许 多 编 译 开 发 商 在 标 准 C 上 增 加 了 对 中 断 的 支 持, 提 供 新 的 关 键 字 用 于 标 示 中 断 服 务 程 序 (ISR), 类 似 于 interrupt #program interrupt 等 当 一 个 函 数 被 定 义 为 ISR 的 时 候, 编 译 器 会 自 动 为 该 函 数 增 加 中 断 服 务 程 序 所 需 要 的 中 断 现 场 入 栈 和 出 栈 代 码 中 断 服 务 程 序 需 要 满 足 如 下 要 求 : (1) 不 能 返 回 值 ; (2) 不 能 向 ISR 传 递 参 数 ; (3) ISR 应 该 尽 可 能 的 短 小 精 悍 ; (4) printf(char * lpformatstring, ) 函 数 会 带 来 重 入 和 性 能 问 题, 不 能 在 ISR 中 采 用 在 某 项 目 的 开 发 中, 我 们 设 计 了 一 个 队 列, 在 中 断 服 务 程 序 中, 只 是 将 中 断 类 型 添 加 入 该 队 列 中, 在 主 程 序 的 死 循 环 中 不 断 扫 描 中 断 队 列 是 否 有 中 断, 有 则 取 出 队 列 中 的 第 一 个 中 断 类 型, 进 行 相 应 处 理 /* 存 放 中 断 的 队 列 */ typedef struct tagintqueue int inttype; /* 中 断 类 型 */ struct tagintqueue *next; IntQueue; IntQueue lpintqueuehead; interrupt ISRexample () 27

int inttype; inttype = GetSystemType(); QueueAddTail(lpIntQueueHead, inttype);/* 在 队 列 尾 加 入 新 的 中 断 */ 在 主 程 序 循 环 中 判 断 是 否 有 中 断 : While(1) If(!IsIntQueueEmpty() ) inttype = GetFirstInt(); switch(inttype) /* 是 不 是 很 象 WIN32 程 序 的 消 息 解 析 函 数? */ /* 对, 我 们 的 中 断 类 型 解 析 很 类 似 于 消 息 驱 动 */ case xxx: /* 我 们 称 其 为 " 中 断 驱 动 " 吧? */ break; case xxx: break; 按 上 述 方 法 设 计 的 中 断 服 务 程 序 很 小, 实 际 的 工 作 都 交 由 主 程 序 执 行 了 硬 件 驱 动 模 块 一 个 硬 件 驱 动 模 块 通 常 应 包 括 如 下 函 数 : (1) 中 断 服 务 程 序 ISR (2) 硬 件 初 始 化 a. 修 改 寄 存 器, 设 置 硬 件 参 数 ( 如 UART 应 设 置 其 波 特 率,AD/DA 设 备 应 设 置 其 采 样 速 率 等 ); b. 将 中 断 服 务 程 序 入 口 地 址 写 入 中 断 向 量 表 : /* 设 置 中 断 向 量 表 */ m_myptr = make_far_pointer(0l); /* 返 回 void far 型 指 针 void far * */ m_myptr += ITYPE_UART; /* ITYPE_UART: uart 中 断 服 务 程 序 */ /* 相 对 于 中 断 向 量 表 首 地 址 的 偏 移 */ 28

*m_myptr = &UART _Isr; /* UART _Isr:UART 的 中 断 服 务 程 序 */ (3) 设 置 CPU 针 对 该 硬 件 的 控 制 线 a. 如 果 控 制 线 可 作 PIO( 可 编 程 I/O) 和 控 制 信 号 用, 则 设 置 CPU 内 部 对 应 寄 存 器 使 其 作 为 控 制 信 号 ; b. 设 置 CPU 内 部 的 针 对 该 设 备 的 中 断 屏 蔽 位, 设 置 中 断 方 式 ( 电 平 触 发 还 是 边 缘 触 发 ) (4) 提 供 一 系 列 针 对 该 设 备 的 操 作 接 口 函 数 例 如, 对 于 LCD, 其 驱 动 模 块 应 提 供 绘 制 像 素 画 线 绘 制 矩 阵 显 示 字 符 点 阵 等 函 数 ; 而 对 于 实 时 钟, 其 驱 动 模 块 则 需 提 供 获 取 时 间 设 置 时 间 等 函 数 C 的 面 向 对 象 化 在 面 向 对 象 的 语 言 里 面, 出 现 了 类 的 概 念 类 是 对 特 定 数 据 的 特 定 操 作 的 集 合 体 类 包 含 了 两 个 范 畴 : 数 据 和 操 作 而 C 语 言 中 的 struct 仅 仅 是 数 据 的 集 合, 我 们 可 以 利 用 函 数 指 针 将 struct 模 拟 为 一 个 包 含 数 据 和 操 作 的 " 类 " 下 面 的 C 程 序 模 拟 了 一 个 最 简 单 的 " 类 ": #ifndef C_Class #define C_Class struct #endif C_Class A C_Class A *A_this; /* this 指 针 */ void (*Foo)(C_Class A *A_this); /* 行 为 : 函 数 指 针 */ int a; /* 数 据 */ int b; ; 我 们 可 以 利 用 C 语 言 模 拟 出 面 向 对 象 的 三 个 特 性 : 封 装 继 承 和 多 态, 但 是 更 多 的 时 候, 我 们 只 是 需 要 将 数 据 与 行 为 封 装 以 解 决 软 件 结 构 混 乱 的 问 题 C 模 拟 面 向 对 象 思 想 的 目 的 不 在 于 模 拟 行 为 本 身, 而 在 于 解 决 某 些 情 况 下 使 用 C 语 言 编 程 时 程 序 整 体 框 架 结 构 分 散 数 据 和 函 数 脱 节 的 问 题 我 们 在 后 续 章 节 会 看 到 这 样 的 例 子 总 结 本 篇 介 绍 了 嵌 入 式 系 统 编 程 软 件 架 构 方 面 的 知 识, 主 要 包 括 模 块 划 分 多 任 务 还 是 单 任 务 选 取 单 任 务 程 序 典 型 架 构 中 断 服 务 程 序 硬 件 驱 动 模 块 设 计 等, 从 宏 观 上 给 出 了 一 个 嵌 入 式 系 统 软 件 所 包 含 的 主 要 元 素 请 记 住 : 软 件 结 构 是 软 件 的 灵 魂! 结 构 混 乱 的 程 序 面 目 可 憎, 调 试 测 试 维 护 升 级 都 极 度 困 难 小 力 力 力 2005-09-21 17:29 29

C 语 言 嵌 入 式 系 统 编 程 修 炼 之 三 : 内 存 操 作 作 者 : 宋 宝 华 更 新 日 期 :2005-07-22 数 据 指 针 在 嵌 入 式 系 统 的 编 程 中, 常 常 要 求 在 特 定 的 内 存 单 元 读 写 内 容, 汇 编 有 对 应 的 MOV 指 令, 而 除 C/C++ 以 外 的 其 它 编 程 语 言 基 本 没 有 直 接 访 问 绝 对 地 址 的 能 力 在 嵌 入 式 系 统 的 实 际 调 试 中, 多 借 助 C 语 言 指 针 所 具 有 的 对 绝 对 地 址 单 元 内 容 的 读 写 能 力 以 指 针 直 接 操 作 内 存 多 发 生 在 如 下 几 种 情 况 : (1) 某 I/O 芯 片 被 定 位 在 CPU 的 存 储 空 间 而 非 I/O 空 间, 而 且 寄 存 器 对 应 于 某 特 定 地 址 ; (2) 两 个 CPU 之 间 以 双 端 口 RAM 通 信,CPU 需 要 在 双 端 口 RAM 的 特 定 单 元 ( 称 为 mail box) 书 写 内 容 以 在 对 方 CPU 产 生 中 断 ; (3) 读 取 在 ROM 或 FLASH 的 特 定 单 元 所 烧 录 的 汉 字 和 英 文 字 模 譬 如 : unsigned char *p = (unsigned char *)0xF000FF00; *p=11; 以 上 程 序 的 意 义 为 在 绝 对 地 址 0xF0000+0xFF00(80186 使 用 16 位 段 地 址 和 16 位 偏 移 地 址 ) 写 入 11 在 使 用 绝 对 地 址 指 针 时, 要 注 意 指 针 自 增 自 减 操 作 的 结 果 取 决 于 指 针 指 向 的 数 据 类 别 上 例 中 p++ 后 的 结 果 是 p= 0xF000FF01, 若 p 指 向 int, 即 : int *p = (int *)0xF000FF00; p++( 或 ++p) 的 结 果 等 同 于 :p = p+sizeof(int), 而 p-( 或 -p) 的 结 果 是 p = p-sizeof(int) 同 理, 若 执 行 : long int *p = (long int *)0xF000FF00; 则 p++( 或 ++p) 的 结 果 等 同 于 :p = p+sizeof(long int), 而 p-( 或 -p) 的 结 果 是 p = p-sizeof(long int) 记 住 :CPU 以 字 节 为 单 位 编 址, 而 C 语 言 指 针 以 指 向 的 数 据 类 型 长 度 作 自 增 和 自 减 理 解 这 一 点 对 于 以 指 针 直 接 操 作 内 存 是 相 当 重 要 的 函 数 指 针 首 先 要 理 解 以 下 三 个 问 题 : 30

(1)C 语 言 中 函 数 名 直 接 对 应 于 函 数 生 成 的 指 令 代 码 在 内 存 中 的 地 址, 因 此 函 数 名 可 以 直 接 赋 给 指 向 函 数 的 指 针 ; (2) 调 用 函 数 实 际 上 等 同 于 " 调 转 指 令 + 参 数 传 递 处 理 + 回 归 位 置 入 栈 ", 本 质 上 最 核 心 的 操 作 是 将 函 数 生 成 的 目 标 代 码 的 首 地 址 赋 给 CPU 的 PC 寄 存 器 ; (3) 因 为 函 数 调 用 的 本 质 是 跳 转 到 某 一 个 地 址 单 元 的 code 去 执 行, 所 以 可 以 " 调 用 " 一 个 根 本 就 不 存 在 的 函 数 实 体, 晕? 请 往 下 看 : 请 拿 出 你 可 以 获 得 的 任 何 一 本 大 学 微 型 计 算 机 原 理 教 材, 书 中 讲 到,186 CPU 启 动 后 跳 转 至 绝 对 地 址 0xFFFF0( 对 应 C 语 言 指 针 是 0xF000FFF0,0xF000 为 段 地 址,0xFFF0 为 段 内 偏 移 ) 执 行, 请 看 下 面 的 代 码 : typedef void (*lpfunction) ( ); /* 定 义 一 个 无 参 数 无 返 回 类 型 的 函 数 指 针 类 型 */ /* 定 义 一 个 函 数 指 针, 指 向 CPU 启 动 后 所 执 行 第 一 条 指 令 的 位 置 */ lpfunction lpreset = (lpfunction)0xf000fff0; lpreset(); /* 调 用 函 数 */ 在 以 上 的 程 序 中, 我 们 根 本 没 有 看 到 任 何 一 个 函 数 实 体, 但 是 我 们 却 执 行 了 这 样 的 函 数 调 用 :lpreset(), 它 实 际 上 起 到 了 " 软 重 启 " 的 作 用, 跳 转 到 CPU 启 动 后 第 一 条 要 执 行 的 指 令 的 位 置 记 住 : 函 数 无 它, 唯 指 令 集 合 耳 ; 你 可 以 调 用 一 个 没 有 函 数 体 的 函 数, 本 质 上 只 是 换 一 个 地 址 开 始 执 行 指 令! 数 组 vs. 动 态 申 请 在 嵌 入 式 系 统 中 动 态 内 存 申 请 存 在 比 一 般 系 统 编 程 时 更 严 格 的 要 求, 这 是 因 为 嵌 入 式 系 统 的 内 存 空 间 往 往 是 十 分 有 限 的, 不 经 意 的 内 存 泄 露 会 很 快 导 致 系 统 的 崩 溃 所 以 一 定 要 保 证 你 的 malloc 和 free 成 对 出 现, 如 果 你 写 出 这 样 的 一 段 程 序 : char * function(void) char *p; p = (char *)malloc( ); if(p==null) ; /* 一 系 列 针 对 p 的 操 作 */ return p; 在 某 处 调 用 function(), 用 完 function 中 动 态 申 请 的 内 存 后 将 其 free, 如 下 : 31

char *q = function(); free(q); 上 述 代 码 明 显 是 不 合 理 的, 因 为 违 反 了 malloc 和 free 成 对 出 现 的 原 则, 即 " 谁 申 请, 就 由 谁 释 放 " 原 则 不 满 足 这 个 原 则, 会 导 致 代 码 的 耦 合 度 增 大, 因 为 用 户 在 调 用 function 函 数 时 需 要 知 道 其 内 部 细 节! 正 确 的 做 法 是 在 调 用 处 申 请 内 存, 并 传 入 function 函 数, 如 下 : char *p=malloc( ); if(p==null) ; function(p); free(p); p=null; 而 函 数 function 则 接 收 参 数 p, 如 下 : void function(char *p) /* 一 系 列 针 对 p 的 操 作 */ 基 本 上, 动 态 申 请 内 存 方 式 可 以 用 较 大 的 数 组 替 换 对 于 编 程 新 手, 笔 者 推 荐 你 尽 量 采 用 数 组! 嵌 入 式 系 统 可 以 以 博 大 的 胸 襟 接 收 瑕 疵, 而 无 法 " 海 纳 " 错 误 毕 竟, 以 最 笨 的 方 式 苦 练 神 功 的 郭 靖 胜 过 机 智 聪 明 却 范 政 治 错 误 走 反 革 命 道 路 的 杨 康 给 出 原 则 : (1) 尽 可 能 的 选 用 数 组, 数 组 不 能 越 界 访 问 ( 真 理 越 过 一 步 就 是 谬 误, 数 组 越 过 界 限 就 光 荣 地 成 全 了 一 个 混 乱 的 嵌 入 式 系 统 ); (2) 如 果 使 用 动 态 申 请, 则 申 请 后 一 定 要 判 断 是 否 申 请 成 功 了, 并 且 malloc 和 free 应 成 对 出 现! 关 键 字 const const 意 味 着 " 只 读 " 区 别 如 下 代 码 的 功 能 非 常 重 要, 也 是 老 生 长 叹, 如 果 你 还 不 知 道 它 们 的 区 别, 而 且 已 经 在 程 序 界 摸 爬 滚 打 多 年, 那 只 能 说 这 是 一 个 悲 哀 : const int a; int const a; const int *a; int * const a; 32

int const * a const; (1) 关 键 字 const 的 作 用 是 为 给 读 你 代 码 的 人 传 达 非 常 有 用 的 信 息 例 如, 在 函 数 的 形 参 前 添 加 const 关 键 字 意 味 着 这 个 参 数 在 函 数 体 内 不 会 被 修 改, 属 于 " 输 入 参 数 " 在 有 多 个 形 参 的 时 候, 函 数 的 调 用 者 可 以 凭 借 参 数 前 是 否 有 const 关 键 字, 清 晰 的 辨 别 哪 些 是 输 入 参 数, 哪 些 是 可 能 的 输 出 参 数 (2) 合 理 地 使 用 关 键 字 const 可 以 使 编 译 器 很 自 然 地 保 护 那 些 不 希 望 被 改 变 的 参 数, 防 止 其 被 无 意 的 代 码 修 改, 这 样 可 以 减 少 bug 的 出 现 const 在 C++ 语 言 中 则 包 含 了 更 丰 富 的 含 义, 而 在 C 语 言 中 仅 意 味 着 :" 只 能 读 的 普 通 变 量 ", 可 以 称 其 为 " 不 能 改 变 的 变 量 "( 这 个 说 法 似 乎 很 拗 口, 但 却 最 准 确 的 表 达 了 C 语 言 中 const 的 本 质 ), 在 编 译 阶 段 需 要 的 常 数 仍 然 只 能 以 #define 宏 定 义! 故 在 C 语 言 中 如 下 程 序 是 非 法 的 : const int SIZE = 10; char a[size]; /* 非 法 : 编 译 阶 段 不 能 用 到 变 量 */ 关 键 字 volatile C 语 言 编 译 器 会 对 用 户 书 写 的 代 码 进 行 优 化, 譬 如 如 下 代 码 : int a,b,c; a = inword(0x100); /* 读 取 I/O 空 间 0x100 端 口 的 内 容 存 入 a 变 量 */ b = a; a = inword (0x100); /* 再 次 读 取 I/O 空 间 0x100 端 口 的 内 容 存 入 a 变 量 */ c = a; 很 可 能 被 编 译 器 优 化 为 : int a,b,c; a = inword(0x100); /* 读 取 I/O 空 间 0x100 端 口 的 内 容 存 入 a 变 量 */ b = a; c = a; 但 是 这 样 的 优 化 结 果 可 能 导 致 错 误, 如 果 I/O 空 间 0x100 端 口 的 内 容 在 执 行 第 一 次 读 操 作 后 被 其 它 程 序 写 入 新 值, 则 其 实 第 2 次 读 操 作 读 出 的 内 容 与 第 一 次 不 同,b 和 c 的 值 应 该 不 同 在 变 量 a 的 定 义 前 加 上 volatile 关 键 字 可 以 防 止 编 译 器 的 类 似 优 化, 正 确 的 做 法 是 : volatile int a; volatile 变 量 可 能 用 于 如 下 几 种 情 况 : (1) 并 行 设 备 的 硬 件 寄 存 器 ( 如 : 状 态 寄 存 器, 例 中 的 代 码 属 于 此 类 ); 33

(2) 一 个 中 断 服 务 子 程 序 中 会 访 问 到 的 非 自 动 变 量 ( 也 就 是 全 局 变 量 ); (3) 多 线 程 应 用 中 被 几 个 任 务 共 享 的 变 量 CPU 字 长 与 存 储 器 位 宽 不 一 致 处 理 在 背 景 篇 中 提 到, 本 文 特 意 选 择 了 一 个 与 CPU 字 长 不 一 致 的 存 储 芯 片, 就 是 为 了 进 行 本 节 的 讨 论, 解 决 CPU 字 长 与 存 储 器 位 宽 不 一 致 的 情 况 80186 的 字 长 为 16, 而 NVRAM 的 位 宽 为 8, 在 这 种 情 况 下, 我 们 需 要 为 NVRAM 提 供 读 写 字 节 字 的 接 口, 如 下 : typedef unsigned char BYTE; typedef unsigned int WORD; /* 函 数 功 能 : 读 NVRAM 中 字 节 * 参 数 :woffset, 读 取 位 置 相 对 NVRAM 基 地 址 的 偏 移 * 返 回 : 读 取 到 的 字 节 值 */ extern BYTE ReadByteNVRAM(WORD woffset) LPBYTE lpaddr = (BYTE*)(NVRAM + woffset * 2); /* 为 什 么 偏 移 要 2? */ return *lpaddr; /* 函 数 功 能 : 读 NVRAM 中 字 * 参 数 :woffset, 读 取 位 置 相 对 NVRAM 基 地 址 的 偏 移 * 返 回 : 读 取 到 的 字 */ extern WORD ReadWordNVRAM(WORD woffset) WORD wtmp = 0; LPBYTE lpaddr; /* 读 取 高 位 字 节 */ lpaddr = (BYTE*)(NVRAM + woffset * 2); /* 为 什 么 偏 移 要 2? */ wtmp += (*lpaddr)*256; /* 读 取 低 位 字 节 */ lpaddr = (BYTE*)(NVRAM + (woffset +1) * 2); /* 为 什 么 偏 移 要 2? */ wtmp += *lpaddr; return wtmp; /* 函 数 功 能 : 向 NVRAM 中 写 一 个 字 节 * 参 数 :woffset, 写 入 位 置 相 对 NVRAM 基 地 址 的 偏 移 * bydata, 欲 写 入 的 字 节 */ 34

extern void WriteByteNVRAM(WORD woffset, BYTE bydata) /* 函 数 功 能 : 向 NVRAM 中 写 一 个 字 */ * 参 数 :woffset, 写 入 位 置 相 对 NVRAM 基 地 址 的 偏 移 * wdata, 欲 写 入 的 字 */ extern void WriteWordNVRAM(WORD woffset, WORD wdata) 子 贡 问 曰 :Why 偏 移 要 乘 以 2? 子 曰 : 请 看 图 1,16 位 80186 与 8 位 NVRAM 之 间 互 连 只 能 以 地 址 线 A1 对 其 A0,CPU 本 身 的 A0 与 NVRAM 不 连 接 因 此, NVRAM 的 地 址 只 能 是 偶 数 地 址, 故 每 次 以 0x10 为 单 位 前 进! 图 1 CPU 与 NVRAM 地 址 线 连 接 子 贡 再 问 :So why 80186 的 地 址 线 A0 不 与 NVRAM 的 A0 连 接? 子 曰 : 请 看 IT 论 语 之 微 机 原 理 篇, 那 里 面 讲 述 了 关 于 计 算 机 组 成 的 圣 人 之 道 总 结 本 篇 主 要 讲 述 了 嵌 入 式 系 统 C 编 程 中 内 存 操 作 的 相 关 技 巧 掌 握 并 深 入 理 解 关 于 数 据 指 针 函 数 指 针 动 态 申 请 内 存 const 及 volatile 关 键 字 等 的 相 关 知 识, 是 一 个 优 秀 的 C 语 言 程 序 设 计 师 的 基 本 要 求 当 我 们 已 经 牢 固 掌 握 了 上 述 技 巧 后, 我 们 就 已 经 学 会 了 C 语 言 的 99%, 因 为 C 语 言 最 精 华 的 内 涵 皆 在 内 存 操 作 中 体 现 我 们 之 所 以 在 嵌 入 式 系 统 中 使 用 C 语 言 进 行 程 序 设 计,99% 是 因 为 其 强 大 的 内 存 操 作 能 力! 如 果 你 爱 编 程, 请 你 爱 C 语 言 ; 如 果 你 爱 C 语 言, 请 你 爱 指 针 ; 35

如 果 你 爱 指 针, 请 你 爱 指 针 的 指 针! C 语 言 嵌 入 式 系 统 编 程 修 炼 之 四 : 屏 幕 操 作 作 者 : 宋 宝 华 更 新 日 期 :2005-07-22 汉 字 处 理 现 在 要 解 决 的 问 题 是, 嵌 入 式 系 统 中 经 常 要 使 用 的 并 非 是 完 整 的 汉 字 库, 往 往 只 是 需 要 提 供 数 量 有 限 的 汉 字 供 必 要 的 显 示 功 能 例 如, 一 个 微 波 炉 的 LCD 上 没 有 必 要 提 供 显 示 " 电 子 邮 件 " 的 功 能 ; 一 个 提 供 汉 字 显 示 功 能 的 空 调 的 LCD 上 不 需 要 显 示 一 条 " 短 消 息 ", 诸 如 此 类 但 是 一 部 手 机 小 灵 通 则 通 常 需 要 包 括 较 完 整 的 汉 字 库 如 果 包 括 的 汉 字 库 较 完 整, 那 么, 由 内 码 计 算 出 汉 字 字 模 在 库 中 的 偏 移 是 十 分 简 单 的 : 汉 字 库 是 按 照 区 位 的 顺 序 排 列 的, 前 一 个 字 节 为 该 汉 字 的 区 号, 后 一 个 字 节 为 该 字 的 位 号 每 一 个 区 记 录 94 个 汉 字, 位 号 则 为 该 字 在 该 区 中 的 位 置 因 此, 汉 字 在 汉 字 库 中 的 具 体 位 置 计 算 公 式 为 :94*( 区 号 -1)+ 位 号 -1 减 1 是 因 为 数 组 是 以 0 为 开 始 而 区 号 位 号 是 以 1 为 开 始 的 只 需 乘 上 一 个 汉 字 字 模 占 用 的 字 节 数 即 可, 即 :(94*( 区 号 -1)+ 位 号 -1)* 一 个 汉 字 字 模 占 用 字 节 数, 以 16*16 点 阵 字 库 为 例, 计 算 公 式 则 为 :(94*( 区 号 -1)+( 位 号 -1))*32 汉 字 库 中 从 该 位 置 起 的 32 字 节 信 息 记 录 了 该 字 的 字 模 信 息 对 于 包 含 较 完 整 汉 字 库 的 系 统 而 言, 我 们 可 以 以 上 述 规 则 计 算 字 模 的 位 置 但 是 如 果 仅 仅 是 提 供 少 量 汉 字 呢? 譬 如 几 十 至 几 百 个? 最 好 的 做 法 是 : 定 义 宏 : # define EX_FONT_CHAR(value) # define EX_FONT_UNICODE_VAL(value) (value), # define EX_FONT_ANSI_VAL(value) (value), 定 义 结 构 体 : typedef struct _wide_unicode_font16x16 WORD value; /* 内 码 */ BYTE data[32]; /* 字 模 点 阵 */ Unicode; #define CHINESE_CHAR_NUM /* 汉 字 数 量 */ 字 模 的 存 储 用 数 组 : Unicode chinese[chinese_char_num] = EX_FONT_CHAR(" 业 ") EX_FONT_UNICODE_VAL(0x4e1a) 36