计算机
类型
可以朗读
语音朗读
220千字
字数
2016-11-01
发行日期
展开全部
主编推荐语
深入讲解C语言,提升嵌入式开发能力。
内容简介
这是一本从本质上深入讲解C语言的书,以嵌入式linux平台软件开发为目标平台,结合linux内核源代码、uboot源代码等嵌入式软件工程师常用的源码中用到的主要C语言技巧和难点(譬如C语言复杂表达式、container_of宏、静态库动态库、内核链表等)进行分析讲解。学习本书可以极大提升复杂C语言代码阅读能力及编写调试能力,尤其对需要从事嵌入式底层驱动软件开发的人员有极大帮助。
目录
- 版权信息
- 前言
- 参与本书整理和编写的学生
- 第1章 C语言与内存
- 1.1 引言
- 1.2 计算机程序运行的目的
- 1.2.1 什么是程序
- 1.2.2 计算机运行程序的目的
- 1.2.3 静态内存SRAM和动态内存DRAM
- 1.2.4 冯·诺伊曼结构和哈佛结构
- 1.2.5 总结:程序运行为什么需要内存呢
- 1.2.6 深入思考:如何管理内存(无OS时,有OS时)
- 1.3 位、字节、半字、字的概念和内存位宽
- 1.3.1 深入了解内存(硬件和逻辑两个角度)
- 1.3.2 内存的逻辑抽象图(内存的编程模型)
- 1.3.3 位和字节
- 1.3.4 字和半字
- 1.3.5 内存位宽(硬件和逻辑两个角度)
- 1.4 内存编址和寻址、内存对齐
- 1.4.1 内存编址方法
- 1.4.2 关键:内存编址是以字节为单位
- 1.4.3 内存和数据类型的关系
- 1.4.4 内存对齐
- 1.5 C语言如何操作内存
- 1.5.1 C语言对内存地址的封装
- 1.5.2 用指针来间接访问内存
- 1.5.3 指针类型的含义
- 1.5.4 用数组来管理内存
- 1.6 内存管理之结构体
- 1.6.1 数据结构这门学问的意义
- 1.6.2 最简单的数据结构:数组
- 1.6.3 数组的优缺点
- 1.6.4 结构体隆重登场
- 1.6.5 题外话:结构体内嵌指针实现面向对象
- 1.7 内存管理之栈(stack)
- 1.7.1 什么是栈
- 1.7.2 栈管理内存的特点(小内存、自动化)
- 1.7.3 栈的应用举例:局部变量和函数调用
- 1.7.4 栈的约束(预定栈大小不灵活,怕溢出)
- 1.8 内存管理之堆
- 1.8.1 什么是堆
- 1.8.2 堆管理内存的特点(大块内存、手工分配/使用/释放)
- 1.8.3 C语言操作堆内存的接口(malloc/free)
- 1.8.4 堆的优势和劣势(管理大块内存、灵活、容易内存泄漏)
- 1.8.5 静态存储区
- 课后题
- 第2章 C语言位操作
- 2.1 引言
- 2.2 常用位操作符
- 2.2.1 位与(&)
- 2.2.2 位或(|)
- 2.2.3 位取反(~)
- 2.2.4 位异或(^)
- 2.2.5 左移位(<<)
- 2.2.6 右移位(>>)
- 2.3 位操作与寄存器
- 2.3.1 寄存器的操作
- 2.3.2 寄存器特定位清零用&
- 2.3.3 寄存器特定位置1用|
- 2.3.4 寄存器特定位取反用~
- 2.4 位运算构建特定二进制数
- 2.4.1 使用移位获取特定位为1的二进制数
- 2.4.2 结合位取反获取特定位为0的二进制数
- 2.4.3 总结
- 2.5 位运算实战演练1
- 2.5.1 给定整型数a,设置a的bit3,保证其他位不变
- 2.5.2 给定整型数a,设置a的bit3~bit7,保持其他位不变
- 2.5.3 给定整型数a,清除a的bit15,保证其他位不变
- 2.5.4 给定整型数a,清除a的bit15~bit23,保持其他位不变
- 2.5.5 给定整型数a,取出a的bit3~bit8
- 2.5.6 用C语言给寄存器a的bit7~bit17赋值937(其余位不受影响)
- 2.6 位运算实战演练2
- 2.6.1 用C语言将寄存器a的bit7~bit17中的值加17(其余位不受影响)
- 2.6.2 用C语言给寄存器a的bit7~bit17赋值937,同时给bit21~bit25赋值17
- 2.7 技术升级:用宏定义来完成位运算
- 2.7.1 直接用宏来置位
- 2.7.2 直接用宏来复位
- 2.7.3 截取变量的部分连续位
- 课后题
- 第3章 指针才是C语言的精髓
- 3.1 引言
- 3.2 指针到底是什么
- 3.2.1 普通变量
- 3.2.2 指针变量
- 3.2.3 变量空间的首字节地址,作为整个空间的地址
- 3.2.4 指针变量的类型作用
- 3.2.5 为什么需要指针
- 3.2.6 高级语言如Java、C#的指针到哪里去了
- 3.2.7 指针使用之三部曲
- 3.3 理解指针符号
- 3.3.1 星号*的理解
- 3.3.2 取地址符&的理解
- 3.3.3 指针变量的初始化和指针变量赋值之间的区别
- 3.3.4 左值与右值
- 3.3.5 定义指针后,需要关心的一些内容
- 3.4 野指针与段错误问题
- 3.4.1 什么是野指针
- 3.4.2 野指针可能引发的危害
- 3.4.3 野指针产生的原因
- 3.4.4 如何避免野指针
- 3.4.5 NULL到底是什么
- 3.4.6 段错误产生的原因汇总
- 3.5 const关键字与指针
- 3.5.1 什么是const
- 3.5.2 const对于普通变量的修饰
- 3.5.3 const修饰指针的三种形式
- 3.5.4 const的变量真的不能改吗
- 3.5.5 为什么要用const
- 3.5.6 有关变量和常量的探讨
- 3.6 深入学习数组
- 3.6.1 为什么需要数组
- 3.6.2 从编译器角度理解数组
- 3.6.3 从内存角度理解数组
- 3.6.4 一维数组中几个关键符号的理解
- 3.7 指针与数组的天生“姻缘”
- 3.7.1 如何使用指针访问数组
- 3.7.2 从内存角度理解指针访问数组的实质
- 3.7.3 指针与数组类型的匹配问题
- 3.7.4 总结:指针类型决定了指针如何参与运算
- 3.8 指针类型与强制类型转换
- 3.8.1 变量数据类型的作用
- 3.8.2 数据的存入和读取
- 3.8.3 普通变量的强制转换
- 3.8.4 指针变量数据类型的含义
- 3.8.5 指针变量数据类型的强制转换
- 3.9 指针、数组与sizeof运算符
- 3.9.1 char str[]="hello"; sizeof(str) ,sizeof(str[0]) ,strlen(str)
- 3.9.2 char str[]="hello"; char *p=str; sizeof(*p)
- 3.9.3 int b[100]; sizeof(b)
- 3.9.4 数组的传参
- 3.9.5 #define和typedef的区别
- 3.10 指针与函数传参
- 3.10.1 普通传参
- 3.10.2 传递地址(指针)
- 3.10.3 传递数组
- 3.10.4 传递结构体
- 3.10.5 传递普通值和传递地址的异同,以及传递地址(指针)应该遵循的原则
- 3.11 输入型参数与输出型参数
- 3.11.1 函数为什么需要传参和返回值
- 3.11.2 函数传参中为什么使用const指针
- 3.11.3 总结
- 课后题
- 第4章 C语言复杂表达式与指针高级应用
- 4.1 引言
- 4.2 指针数组与数组指针
- 4.2.1 简单理解指针数组与数组指针
- 4.2.2 分析指针数组与数组指针的表达式
- 4.3 函数指针与typedef
- 4.3.1 函数指针的实质(还是指针变量)
- 4.3.2 函数指针的书写和分析方法
- 4.3.3 typedef关键字的用法
- 4.4 函数指针实战1——用函数指针调用执行函数
- 4.5 函数指针实战2——结构体内嵌函数指针实现分层
- 4.6 再论typedef
- 4.6.1 轻松理解和应用typedef
- 4.6.2 typedef与#define宏的区别
- 4.6.3 typedef与struct
- 4.6.4 typedef与const
- 4.6.5 使用typedef的重要意义
- 4.6.6 二重指针
- 4.7 二维数组
- 4.7.1 二维数组的内存映像
- 4.7.2 识别第一维和第二维
- 4.7.3 数组名代表数组首元素的地址
- 4.7.4 指针访问二维数组的两种方式
- 4.7.5 总结
- 课后题
- 第5章 数组&字符串&结构体&共用体&枚举
- 5.1 引言
- 5.2 程序中的内存从哪里来
- 5.2.1 管理方式:栈(stack)、堆(heap)、数据区(.data)
- 5.2.2 栈内存特点详解
- 5.3 堆
- 5.3.1 堆内存特点详解
- 5.3.2 使用堆内存注意事项
- 5.3.3 malloc的一些细节表现
- 5.4 内存中的各个段
- 5.4.1 代码段、数据段、bss段
- 5.4.2 特殊数据会被放到代码段
- 5.4.3 未初始化或显式初始化为0的全局变量放在bss段
- 5.4.4 内存管理方式的总结
- 5.5 C语言的字符串类型
- 5.5.1 C语言使用指针来管理字符串
- 5.5.2 C语言中字符串的本质:指向字符串的存放空间的指针
- 5.5.3 指向字符串的指针变量空间和字符串存放的空间是分开的
- 5.5.4 存储多个字符的两种方式——字符串和字符数组
- 5.6 字符串和字符数组的细节
- 5.6.1 字符数组的初始化、sizeof以及strlen
- 5.6.2 字符串的初始化与sizeof、strlen
- 5.6.3 字符数组与字符串的本质差异
- 5.7 结构体概述
- 5.7.1 结构体使用时先定义结构体类型,再用类型定义变量
- 5.7.2 从数组到结构体的进步之处
- 5.7.3 结构体变量中的元素如何访问
- 5.8 结构体的对齐访问
- 5.8.1 结构体对齐访问实例
- 5.8.2 结构体为何要对齐访问
- 5.8.3 结构体对齐的规则和运算
- 5.8.4 手动对齐
- 5.8.5 GCC推荐的对齐指令:_attribute_((packed))和_attribute_((aligned(n)))
- 5.9 offsetof宏与container_of宏
- 5.9.1 通过结构体指针访问各结构体成员的原理
- 5.9.2 offsetof宏
- 5.9.3 container_of宏
- 5.9.4 学习指南和要求
- 5.10 共用体(union)
- 5.10.1 共用体的类型声明、变量定义和使用
- 5.10.2 共用体和结构体的区别
- 5.10.3 共用体的主要用途
- 5.11 大小端模式
- 5.11.1 什么是大小端模式
- 5.11.2 用union来测试机器的大小端模式
- 5.11.3 用指针方式来测试机器的大小端
- 5.11.4 通信系统中的大小端(数组的大小端)
- 5.12 枚举enum
- 5.12.1 枚举的作用是什么
- 5.12.2 C语言为何需要枚举
- 5.12.3 宏定义和枚举的区别
- 5.12.4 枚举的定义形式
- 课后题
- 第6章 C语言的预处理、函数和函数库
- 6.1 引言
- 6.2 C语言为什么需要编译链接
- 6.2.1 编译链接的流程
- 6.2.2 编译链接中各种文件扩展名的含义
- 6.3 预处理详解
- 6.3.1 C语言预处理的意义
- 6.3.2 预处理涉及的内容
- 6.3.3 使用GCC进行编译和链接的过程
- 6.4 常见的预处理详解
- 6.4.1 文件包含
- 6.4.2 注释
- 6.4.3 宏定义
- 6.4.4 条件编译
- 6.5 函数的本质
- 6.5.1 C语言为什么会有函数
- 6.5.2 函数书写的一般原则
- 6.5.3 函数是动词、变量是名词(面向对象语言中分别叫方法和成员变量)
- 6.5.4 函数的实质是数据处理器
- 6.6 函数的基本使用
- 6.6.1 函数三要素:定义、声明、调用
- 6.6.2 函数原型和作用
- 6.7 递归函数
- 6.7.1 函数的调用机制
- 6.7.2 递归函数
- 6.7.3 使用递归的原则:收敛性、栈溢出
- 6.7.4 递归与循环的区别
- 6.8 库函数
- 6.8.1 什么是函数库
- 6.8.2 函数库的由来
- 6.8.3 函数库的提供形式:静态链接库与动态链接库
- 6.8.4 库函数的使用
- 6.9 常见的库函数之字符串函数
- 6.9.1 什么是字符串
- 6.9.2 字符串处理函数
- 6.9.3 man手册的引入
- 6.9.4 man手册的使用
- 6.9.5 常用的字符串处理函数
- 6.10 常见的库函数之数学库函数
- 6.10.1 数学库函数
- 6.10.2 计算开平方
- 6.10.3 链接时加-lm
- 6.11 制作静态链接库并使用
- 6.12 制作动态链接库并使用
- 课后题
- 第7章 存储类&作用域&生命周期&链接属性
- 7.1 引言
- 7.2 概念解析
- 7.2.1 存储类
- 7.2.2 作用域
- 7.2.3 生命周期
- 7.2.4 链接属性
- 7.3 Linux下C程序的内存映像
- 7.3.1 代码段、rodata段(只读数据段)
- 7.3.2 数据段、bss段
- 7.3.3 堆
- 7.3.4 文件映射区
- 7.3.5 栈
- 7.3.6 内核映射区
- 7.3.7 操作系统下和裸机下C程序加载执行的差异
- 7.4 存储类相关的关键字1
- 7.4.1 auto
- 7.4.2 static
- 7.4.3 register
- 7.5 存储类相关的关键字2
- 7.5.1 extern
- 7.5.2 volatile
- 7.5.3 restrict
- 7.5.4 typedef
- 7.6 作用域详解
- 7.6.1 局部变量的代码块作用域
- 7.6.2 函数名和全局变量的文件作用域
- 7.7 变量的生命周期
- 7.7.1 研究变量生命周期的意义
- 7.7.2 栈变量的生命周期
- 7.7.3 堆变量的生命周期
- 7.7.4 数据段、bss段变量的生命周期
- 7.7.5 代码段、只读段的生命周期
- 7.8 链接属性
- 7.8.1 C语言程序的组织架构:多个C文件+多个h文件
- 7.8.2 编译以文件为单位、链接以工程为单位
- 7.8.3 三种链接属性:外连接、内链接、无链接
- 7.8.4 函数和全局变量的命名冲突问题
- 7.8.5 static的第二种用法:修饰全局变量和函数
- 课后题
- 第8章 C语言关键细节讨论
- 8.1 引言
- 8.2 操作系统概述
- 8.2.1 什么是操作系统
- 8.2.2 C库函数
- 8.2.3 操作系统的重大意义
- 8.3 main函数返回值
- 8.3.1 普通函数的返回值
- 8.3.2 main函数的返回值
- 8.3.3 谁调用了main函数
- 8.4 argc、argv与main函数的传参
- 8.5 void类型的本质
- 8.6 C语言中的NULL
- 8.6.1 NULL的定义
- 8.6.2 '\0'、'0'、0 和NULL的区别
- 8.7 运算中的临时匿名变量
- 8.7.1 C语言和汇编语言的区别
- 8.7.2 强制类型转换
- 8.7.3 使用临时变量来理解不同数据类型之间的运算
- 8.8 顺序结构
- 8.8.1 C语言中的结构
- 8.8.2 编译过程中的顺序结构
- 8.8.3 思考:为什么本质都是顺序结构
- 8.9 程序调试
- 8.9.1 程序调试手段
- 8.9.2 调试(DEBUG)版本和发行(RELEASE)版本的区别
- 8.9.3 debug宏的使用方法
- 课后题
- 第9章 链表&状态机&多线程
- 9.1 引言
- 9.2 链表的引入
- 9.2.1 数组的缺陷
- 9.2.2 感性地认识链表
- 9.2.3 链表的作用是什么
- 9.3 单链表的实现之构建第一个节点
- 9.3.1 单向链表
- 9.3.2 单向链表的结构
- 9.3.3 单链表的节点构成
- 9.3.4 使用堆内存创建一个节点
- 9.3.5 链表的头指针
- 9.3.6 构建第一个简单的链表
- 9.4 单链表的实现之从尾部插入节点
- 9.4.1 从尾部插入节点
- 9.4.2 构建第一个简单的链表
- 9.4.3 什么是头节点
- 9.5 单链表的算法之从头部插入节点
- 9.5.1 链表头部插入思路解析
- 9.5.2 箭头非指向
- 9.6 单链表的算法之遍历节点
- 9.6.1 什么是遍历
- 9.6.2 如何遍历单链表
- 9.6.3 代码分析
- 9.7 单链表的算法之删除节点
- 9.7.1 为什么要删除节点
- 9.7.2 注意堆内存的释放
- 9.7.3 设计一个删除节点算法
- 9.8 单链表的算法之逆序
- 9.8.1 什么是链表的逆序
- 9.8.2 单链表的逆序算法分析
- 9.8.3 编程实现逆序算法
- 9.8.4 数据结构与算法的关系
- 9.9 双链表的引入和基本实现
- 9.9.1 单链表的优缺点
- 9.9.2 双链表的结构
- 9.10 双链表的算法之插入节点
- 9.10.1 尾部插入
- 9.10.2 头部插入
- 9.11 双链表的算法之遍历
- 9.11.1 正向遍历
- 9.11.2 逆向遍历
- 9.12 双链表的算法之删除节点
- 9.13 Linux内核链表
- 9.13.1 前述链表数据区域的局限性
- 9.13.2 解决思路:数据区的结构体的封装由用户实现,通用部分通过调用函数实现
- 9.13.3 内核链表的设计思路
- 9.13.4 list.h文件简介
- 9.14 内核链表的基本算法和使用简介
- 9.14.1 内核链表的常用操作
- 9.14.2 内核链表的使用实践
- 9.15 什么是状态机
- 9.15.1 有限状态机
- 9.15.2 两种状态机:Moore型和Mealy型
- 9.15.3 状态机的主要用途
- 9.15.4 状态机解决了什么问题
- 9.16 用C语言实现简单的状态机
- 9.16.1 题目:开锁状态机
- 9.16.2 题目分析
- 9.17 多线程简介
- 9.17.1 操作系统下的并行执行机制
- 9.17.2 进程和线程的区别和联系
- 9.17.3 多线程的优势
- 课后题
- 第10章 程序员和编译器的暧昧
- 10.1 引言
- 10.2 编程工作的演进史
- 10.2.1 CPU与二进制
- 10.2.2 编程语言的革命
- 10.3 程序员、编译器和CPU之间的三角恋
- 10.3.1 程序员与CPU的之间的“翻译”—编译器
- 10.3.2 高级语言与低级语言的差别
- 10.4 像编译器一样思考吧——理论篇
- 10.4.1 编译器的结构
- 10.4.2 语法是什么?语法就是编译器的习性
- 10.5 像编译器一样思考吧——实战篇
- 10.5.1 充分地利用语法规则,写出简洁、高效的代码
- 10.5.2 复杂表达式理解
- 课后题
- 附录 答案
- 第1章 课后题答案
- 第2章 课后题答案
- 第3章 课后题答案
- 第4章 课后题答案
- 第5章 课后题答案
- 第6章 课后题答案
- 第7章 课后题答案
- 第8章 课后题答案
- 第9章 课后题答案
- 第10章 课后题答案
- 欢迎来到异步社区!
展开全部
出版方
人民邮电出版社
人民邮电出版社是工业和信息化部主管的大型专业出版社,成立于1953年10月1日。人民邮电出版社坚持“立足信息产业、面向现代社会、传播科学知识、服务科教兴国”,致力于通信、计算机、电子技术、教材、少儿、经管、摄影、集邮、旅游、心理学等领域的专业图书出版。