第1学时 入门 1
1.1 Linux简介 1
1.2 GNU gcc简介 1
1.2.1 选择GNU标准 1
1.2.2 指定编译器输出 2
1.2.3 运行编译后的程序 2
1.3 用于调试的编译 2
1.4 检查编译器的警告级别 4
1.5 处理编译器的警告消息 5
1.5.1 关于赋值的警告 5
1.5.2 关于未用参数的警告 7
1.5.3 解决关于未用变量的警告 7
1.5.4 解决关于未用字符串的警告 9
1.6 测试C编译器 10
1.7 课时小结 12
1.8 专家答疑 12
1.9 课外作业 12
1.9.1 思考题 12
1.9.2 练习题 12
第2学时 管理源代码 13
2.1 使用源代码管理的好处 13
2.2 有哪些可以选择的工具 13
2.3 为项目设置RCS 13
2.4 创建新的源文件 14
2.5 查看RCS控制的文件 16
2.6 使用RCS子目录 16
2.7 签出文件进行编辑 17
2.8 修改文件 18
2.9 显示修改的内容 19
2.10 注册修改 19
2.11 用rlog命令列出编辑历史记录 20
2.12 嵌入式替换 20
2.13 显示嵌入的RCS信息 22
2.14 使用源文件模板 23
2.14.1 源代码模板 23
2.14.2 包含文件模板 23
2.15 取消锁定的签出 24
2.16 课时小结 24
2.17 专家答疑 24
2.18 课外作业 25
2.18.1 思考题 25
2.18.2 练习题 25
第3学时 编写Linux实用程序 26
3.1 开始使用项目dos_cvrt 26
3.1.1 项目规划 26
3.1.2 签出dos_cvrt.c进行编辑 26
3.1.3 选择包含文件 27
3.1.5 测试带占位程序的实用程序 29
3.1.6 替换占位程序 29
3.1.7 回顾整个项目 33
3.2 使用命令行编辑 34
3.2.1 选择命令行编辑模式 35
3.2.2 进行命令行搜索 35
3.3 课时小结 37
3.4 专家答疑 37
3.5 课外作业 37
3.5.1 思考题 37
3.5.2 练习题 38
第4学时 C语言的模块化编辑 39
4.1 模块化编辑 39
4.2 制作模块化的dos_cvrt.c 39
4.2.1 签出dos_cvrt.c进行编辑 39
4.2.2 将dos_cvrt.c分解为函数 39
4.2.3 改善dos_cvrt 42
4.2.4 将dos_cvrt分解独立的源程序模块 44
4.2.5 声明静态函数 49
4.3 课时小结 50
4.4 专家答疑 50
4.5 课外作业 50
4.5.1 思考题 50
4.5.2 练习题 50
第5学时 Make文件简介 51
5.1 为什么要使用make? 51
5.2 Makefile文件 51
5.2.1 测试make的内部功能 51
5.2.2 命名自己的Makefile文件 52
5.2.3 Makefile的目标文件 52
5.2.4 默认的目标文件 53
5.2.5 标准目标文件名称 54
5.2.6 依赖关系 54
5.3 定义make的宏 55
5.3.1 替代宏的值 56
5.3.2 使用环境变量 56
5.3.3 使用make的-e选项 57
5.4 检查文件的后缀 58
5.5 推理规则 58
5.5.1 测试默认推理规则 58
5.5.2 定义推理规则 59
5.5.3 动作语句 59
5.5.4 内部宏 59
5.5.5 宏CFLAGS 60
5.6 为dos_cvrt使用Makefile文件 60
5.6.1 生成一个Makefile文件 61
5.6.2 测试新的Makefile文件 62
5.6.3 测试局部编译 62
5.7 课时小结 63
5.8 专家答疑 63
5.9 课外作业 63
5.9.1 思考题 63
5.9.2 练习题 63
第6学时 Linux命令行选项处理 65
6.1 命令行处理简介 65
6.1.1 命令行约定 65
6.1.2 使用多个选项 65
6.1.3 组合多个选项 65
6.1.4 使用带参数的选项 65
6.1.5 区分选项和参数 66
6.2 检查看起来像选项的参数 66
6.3 getopt()简介 66
6.4 getopt()函数调用 67
6.5 回顾函数getopt()的原型 67
6.5.1 定义optstring参数 68
6.5.2 定义一个选项处理循环 68
6.6 使用getopt()改进dos_cvrt 69
6.7 GNU长选项扩展 72
6.8 使用GNU函数getopt_long() 73
6.8.1 定义GNU函数getopt_long()的原型 73
6.8.2 理解option结构 73
6.8.3 设置option结构 73
6.8.4 使用一个空option.flag指针 74
6.8.5 使用一个非空option.flag指针 74
6.9 为dos_cvrt增加GNU长选项 75
6.10 课时小结 79
6.11 专家答疑 79
6.12 课外作业 79
6.12.1 思考题 79
6.12.2 练习题 79
第7学时 错误的处理和报告 81
7.1 如何处理错误 81
7.2 UNIX的错误报告 81
7.2.1 指出成功或错误 81
7.2.2 判断错误的原因 81
7.3 旧的errno值 82
7.3.1 通过名称引用错误代码 82
7.3.2 测试特殊错误 82
7.3.3 正确使用errno 83
7.4 新的errno值 83
7.4.1 声明新的errno变量 83
7.4.2 使用新的errno变量 84
7.5 关于errno值的输出 84
7.5.1 使用函数perror() 84
7.5.2 使用数组sys_errlist[] 85
7.5.3 使用函数strerror() 86
7.6 改进dos_cvrt使它友好地报告错误 87
7.6.1 改进模块unix2dos.c 87
7.6.2 改进模块dos2unix.c 89
7.6.3 生成模块putch.c 91
7.6.4 改变包含文件dos_cvrt.h 92
7.6.5 改进Makefile 92
7.6.6 改进模块dos_cvrt.c 93
7.7 测试所有的错误 96
7.8 课时小结 96
7.9 专家答疑 96
7.10 课外作业 97
7.10.1 思考题 97
7.10.2 练习题 97
第8学时 Linux的main程序及其环境 98
8.1 main程序接口 98
8.1.1 组织数组argv[] 98
8.1.2 使用不带argc的argv[] 99
8.1.3 声明第三个main()参数 99
8.1.4 传递外壳的外部变量 99
8.1.5 使用外部指针environ 100
8.2 Linux程序的地址空间 100
8.3 环境操作 107
8.3.1 获取一个环境变量 107
8.3.2 改变环境变量 107
8.3.3 删除环境变量的定义 108
8.3.4 理解环境变化的影响 108
8.4 进程出口值 110
8.4.1 退出代码处理 110
8.4.2 返回一个值 110
8.4.3 使用exit()函数 111
8.4.4 在return和exit()之间选择 111
8.4.5 使用关于return语句的编译器警告 111
8.5 课时小结 112
8.6 专家答疑 112
8.7 课外作业 112
8.7.1 思考题 112
8.7.2 练习题 112
第9学时 有用的调试技术 113
9.1 调试技术简介 113
9.2 调试器的限制 113
9.3 用C宏进行跟踪 113
9.3.1 定义一个TRACE宏 113
9.3.2 改进TRACE宏 115
9.3.3 定义一个参数数量可变的TRACEF 115
9.3.4 定义有条件的调试宏 116
9.4 运行阶段调试跟踪功能 116
9.4.1 用命令行选项控制TRACE 116
9.4.2 使用调试级别 117
9.4.3 通过环境变量来设置调试级别 117
9.5 设计子系统跟踪功能 118
9.5.1 编写子系统跟踪功能 118
9.5.2 子系统跟踪总结 121
9.6 课时小结 122
9.7 专家答疑 122
9.8 课外作业 122
9.8.1 思考题 122
9.8.2 练习题 122
第10学时 静态和共享函数库 124
10.1 C函数库简介 124
10.2 静态函数库 124
10.2.1 回顾进程内存映像 124
10.2.2 实现一个静态函数库 125
10.2.3 使用ar命令来生成档案 125
10.2.4 列出档案的内容 126
10.2.5 链接静态函数库 126
10.3 共享函数库 127
10.3.1 静态函数库的限制 127
10.3.2 生成一个共享函数库 128
10.3.3 链接共享函数库 128
10.3.4 列出共享函数库的引用 129
10.3.5 使用动态装载器 129
10.3.6 独立于代码的编译位置 131
10.3.7 控制共享的内容 132
10.4 函数库的含义 132
10.4.1 静态函数库的优点 132
10.4.2 共享函数的优点 133
10.5 何时该使用静态或共享函数库 134
10.5.1 许可证号 134
10.5.2 安装可靠 134
10.5.3 为了节省而共享 134
10.5.4 动态装载 134
10.6 课时小结 134
10.7 专家答疑 135
10.8 课外作业 135
10.8.1 思考题 135
10.8.2 练习题 135
第11学时 高级字符串函数 137
11.1 高级字符串函数简介 137
11.2 包含字符串函数声明 137
11.3 函数strcasecmp()和strncasecmp() 137
11.3.1 测试一个命令名称匹配的例子 137
11.3.2 比较前n个字符 137
11.3.3 解释返回值 138
11.4 函数strdup() 138
11.4.1 释放字符串 138
11.4.2 测试错误 138
11.5 函数strchr()和strrchr() 139
11.6 函数strpbrk() 139
11.7 函数strspn()和strcspn() 140
11.8 函数strstr() 141
11.9 函数strtok()和strtok_r() 141
11.9.1 函数strtok() 141
11.9.2 分解一个命令行 141
11.9.3 函数strtok_r() 143
11.9.4 strtok()的限制 143
11.9.5 保存状态 144
11.9.6 介绍strtok_r()函数 144
11.10 字符串使用技巧 145
11.10.1 优化strcat()和strcpy()调用 146
11.10.2 有效地使用strncpy()返回值 146
11.10.3 临时编写sprintfcat()函数 146
11.11 课时小结 147
11.12 专家答疑 147
11.13 课外作业 147
11.13.1 思考题 148
11.13.2 练习题 148
第12学时 转换函数 149
12.1 转换函数简介 149
12.2 系列函数atoi()、atol()和atof() 149
12.2.1 详细考察函数atoi()和atol() 150
12.2.2 使用atof()函数 151
12.3 为转换和有效性使用sscanf() 151
12.3.1 将sscanf()用于数字转换 151
12.3.2 测试使用sscanf()的数值转换 153
12.3.3 改善sscanf()转换 153
12.3.4 考虑sscanf()的限制 153
12.4 函数strtol()和strtoul() 154
12.4.1 使用函数strtol() 154
12.4.2 测试函数strtol() 155
12.4.3 测试错误 155
12.4.4 测试转换指针 155
12.4.5 执行多个转换 155
12.4.6 理解基数转换 156
12.4.7 测试上溢和下溢 158
12.4.8 对strtoul()上溢的测试 160
12.5 函数strtod() 160
12.5.1 使用函数strtod() 160
12.5.2 测试数学错误 161
12.6 课时小结 162
12.7 专家答疑 162
12.8 课外作业 163
12.8.1 思考题 163
12.8.2 练习题 163
第13学时 Linux的日期和时间功能 164
13.1 日期和时间支持功能简介 164
13.2 Epoch时间简介 164
13.3 理解当前的Linux日期和时间 165
13.3.1 定义日期和时间数据类型 166
13.3.2 理解为什么时间在运行 166
13.3.3 发现time_t数据类型 166
13.3.4 使用time()获得日期和时间 167
13.4 使用时间转换函数 167
13.4.1 函数ctime() 167
13.4.2 函数localtime()和gmtime() 168
13.4.3 tm结构 168
13.4.4 函数asctime() 170
13.4.5 函数tzset() 170
13.4.6 函数mktime() 171
13.5 定制日期和时间格式 173
13.6 课时小结 176
13.7 专家答疑 177
13.8 课外作业 177
13.8.1 思考题 177
13.8.2 练习题 177
第14学时 用户ID、密码和组管理 179
14.1 简单介绍Linux的管理 179
14.1.1 用户名和uid编号 179
14.1.2 组名和gid编号 180
14.2 身份函数 180
14.2.1 getuid()和geteuid()函数 180
14.2.2 getgid()和getegid()函数 180
14.2.3 uid和gid编号示例 181
14.3 /etc/passwd文件 181
14.3.1 注释域 182
14.3.2 在注释域中使用& 182
14.3.3 搜索密码数据库 182
14.4 密码数据库例程 183
14.4.1 passwd结构 183
14.4.2 处理getpwent()函数的错误 184
14.4.3 fgetpwent()函数 184
14.4.4 putpwent()函数 185
14.4.5 getpwuid()函数 185
14.4.6 getpwnam()函数 185
14.5 组数据库 186
14.5.1 /etc/group文件 186
14.5.2 getgrent()、setgrent()和endgrent()函数 187
14.5.3 group结构 187
14.5.4 fgetgrent()函数 188
14.5.5 getgrgid()函数 188
14.5.6 getgrnam()函数 188
14.6 课时小结 189
14.7 专家答疑 189
14.8 课外作业 189
14.8.1 思考题 189
14.8.2 练习题 189
第15学时 文件系统信息和管理 191
15.1 基本的文件操作 191
15.1.1 删除文件 191
15.1.2 链接文件 191
15.1.3 移动文件 192
15.2 目录操作 192
15.2.1 得到当前的工作目录 193
15.2.2 改变目录 194
15.2.3 创建新目录 194
15.2.4 删除目录 196
15.3 设置umask值 197
15.3.1 为什么要用umask 197
15.3.2 umask的作用范围 197
15.3.3 使用umask()函数 198
15.4 理解文件系统信息 199
15.5 课时小结 203
15.6 专家答疑 203
15.7 课外作业 203
15.7.1 思考题 203
15.7.2 练习题 204
第16学时 临时文件和进程清理 205
16.1 生成临时文件名 205
16.1.1 调用tmpnam()函数 205
16.1.2 调用mkstemp()函数 207
16.1.3 调用tmpfile()函数 209
16.1.4 调用tempnam()函数 210
16.1.5 解释临时文件函数的错误 212
16.2 将文件设为临时文件 213
16.2.1 调用unlink()函数将文件设为临时文件 213
16.2.2 退出之前的清理 213
16.3 课时小结 215
16.4 专家答疑 215
16.5 课外作业 216
16.5.1 思考题 216
16.5.2 练习题 216
第17学时 管道和进程 217
17.1 使用外部进程 217
17.2 管道简介 217
17.2.1 打开管道 217
17.2.2 读管道 218
17.2.3 写管道 220
17.2.4 关闭管道 222
17.2.5 处理断开的管道 223
17.3 system()函数简介 223
17.3.1 system()函数的返回值 224
17.3.2 调用system()函数 224
17.3.3 运行程序示例 225
17.3.4 对system()函数的评价 227
17.4 课时小结 227
17.5 专家答疑 227
17.6 课外作业 227
17.6.1 思考题 227
17.6.2 练习题 228
第18学时 派生进程 229
18.1 进程简介 229
18.1.1 进程ID号 229
18.1.2 父进程和子进程 229
18.1.3 创建进程 229
18.2 fork()函数 230
18.2.1 调用fork()函数 230
18.2.2 运行fork()函数示例 232
18.3 wait()函数族 233
18.3.1 wait()函数的重要性 233
18.3.2 调用wait()函数 234
18.3.3 wait函数族中的其他函数 237
18.4 exec()函数族 237
18.4.1 exec()过程 237
18.4.2 联合fork()函数和exec()函数 237
18.4.3 调用exec()函数 238
18.4.4 exec()函数族中的其他函数 241
18.5 课时小结 242
18.6 专家答疑 242
18.7 课外作业 242
18.7.1 思考题 242
18.7.2 练习题 243
第19学时 信号量 244
19.1 信号量简介 244
19.1.1 和单淋浴间的类比 244
19.1.2 和多淋浴间的类比 245
19.1.3 使用Linux信号量 245
19.1.4 等待信号量 245
19.1.5 通知信号量 245
19.1.6 等待多个实例 246
19.2 创建和访问信号量集 246
19.2.1 标识已存在的信号量集 246
19.2.2 调用semget()函数来创建和访问信号量集 246
19.2.3 初始化信号量集 248
19.3 等待和通知信号量集 249
19.3.1 等待信号量集 250
19.3.2 通知信号量集 251
19.4 释放信号量占用的系统资源 251
19.4.1 删除信号量集 251
19.4.2 使用ipcrm命令释放信号量 252
19.5 模拟使用信号量 253
19.6 课时小结 260
19.7 专家答疑 260
19.8 课外作业 261
19.8.1 思考题 261
19.8.2 练习题 261
第20学时 共享内存 262
20.1 为什么需要共享内存 262
20.2 标识共享内存 262
20.3 创建、连接和释放共享内存 262
20.3.1 创建新的共享内存 262
20.3.2 连接共享内存 263
20.3.3 在指定的地址连接 265
20.3.4 分离共享内存 266
20.3.5 释放共享内存 266
20.4 使用共享内存 267
20.4.1 安全访问共享内存 267
20.4.2 直接引用共享内存而不用信号量 267
20.5 将共享内存应用到一个游戏中 268
20.5.1 回顾战般游戏 268
20.5.2 玩家指令 269
20.5.3 分析玩家1的代码 271
20.5.4 分析玩家2的代码 275
20.5.5 查看其他重要的源模块 275
20.6 课时小结 279
20.7 专家答疑 279
20.8 课外作业 279
20.8.1 思考题 279
20.8.2 练习题 280
第21学时 消息队列 281
21.1 消息队列简介 281
21.1.1 Linux消息队列 281
21.1.2 应用消息类型 281
21.1.3 相互竞争的接收者 282
21.2 管理消息队列 283
21.2.1 创建和访问消息队列 283
21.2.2 释放消息队列 284
21.2.3 消息的结构 285
21.2.4 指定消息的大小 285
21.2.5 发送消息 286
21.2.6 接收消息 287
21.3 呼叫服务器 289
21.4 课时小结 296
21.5 专家答疑 296
21.6 课外作业 296
21.6.1 思考题 297
21.6.2 练习题 297
第22学时 信号 298
22.1 什么是信号 298
22.2 信号SIGINT 298
22.3 信号的术语 299
22.4 可靠的和不可靠的信号 299
22.5 使用信号集 299
22.5.1 清空信号集 299
22.5.2 填充信号集 300
22.5.3 向信号集中添加信号 300
22.5.4 从信号集中删除信号 301
22.5.5 测试信号集中的信号 301
22.6 设置信号响应 301
22.7 捕获信号 303
22.8 封锁和解锁信号 305
22.9 得到挂起的信号 306
22.10 调用sigsuspend()函数 306
22.11 调用alarm()函数 307
22.12 高级信号技术 309
22.12.1 从信号处理程序中调用函数 309
22.12.2 避免可重入代码问题 310
22.12.3 在信号处理程序中处理errno 311
22.12.4 处理EINTR错误 311
22.13 常用的Linux信号 312
22.14 引发Linux信号 313
22.15 课时小结 313
22.16 专家答疑 313
22.17 课外作业 314
22.17.1 思考题 314
22.17.2 练习题 314
第23学时 客户/服务器编程 315
23.1 客户/服务器的优点 315
23.2 设计TQL服务器 315
23.2.1 编译TQL项目 316
23.2.2 使用TQL命令行选项 316
23.2.3 检查TQL的环境变量 317
23.3 理解SQL 317
23.3.1 使用SELECT命令 318
23.3.2 使用表和列 318
23.3.3 第一次启动TQL 318
23.3.4 选择特定的列 319
23.3.5 选择特定的行 320
23.3.6 对行进行排序 320
23.4 分析TQL的源代码 321
23.4.1 分析表代码 322
23.4.2 在tqld中处理信号 322
23.4.3 分析排序模块 323
23.4.4 执行sort命令 327
23.5 课时小结 329
23.6 专家答疑 329
23.7 课外作业 330
23.7.1 思考题 330
23.7.2 练习题 330
第24学时 使用帮助页 331
24.1 介绍man命令 331
24.1.1 使用man命令 331
24.1.2 探索节的内容 331
24.1.3 找到帮助页 332
24.1.4 调试帮助页 332
24.1.5 解决与文档的冲突 335
24.1.6 查看ERRORS部分 337
24.1.7 查看SEE ALSO部分 338
24.1.8 查找文件 339
24.1.9 有文档记录的错误 339
24.2 课时小结 339
24.3 展望未来 339
24.4 专家答疑 340
24.5 课外作业 341
24.5.1 思考题 341
24.5.2 练习题 341
附录 思考题答案 342