第1部分 基础篇
第1章 Linux系统概述 1
1.1 什么是Linux 2
1.2 Linux系统特点及主要功能 2
1.2.1 Linux系统特点 3
1.2.2 Linux系统的主要功能 3
1.3 Linux的内核版本和发行版本 5
1.4 系统的安装 6
1.4.1 系统安装前的准备工作 6
1.4.2 从光盘安装Linux 6
1.4.3 从硬盘安装Linux 22
1.4.4 在虚拟机下安装Linux 22
1.5 Shell的使用 27
1.5.1 Shell简介 27
1.5.2 常见Shell的种类 28
1.5.3 Shell的简单使用 29
1.5.4 通配符 30
1.5.5 引号 31
1.5.6 注释符 33
1.6 Linux常用命令 33
1.6.1 与目录相关的命令 33
1.6.2 与文件相关的命令 34
1.6.3 与网络服务相关的命令 35
1.7 本章小结 35
实战演练 36
第2章 C语言编程基础 37
2.1 C语言的历史背景 38
2.2 C语言的特点 38
2.3 C语言的基本数据类型 39
2.3.1 整型 39
2.3.2 实型 40
2.3.3 字符型 41
2.4 运算符与表达式 43
2.4.1 算术运算符与算术表达式 43
2.4.2 赋值运算符与赋值表达式 44
2.4.3 逗号运算符与逗号表达式 45
2.5 C程序的3种基本结构 46
2.5.1 顺序结构 46
2.5.2 选择结构 47
2.5.3 循环结构 51
2.6 C语言中的数据输入与输出 54
2.6.1 字符输出函数putchar 54
2.6.2 字符输入函数getchar 54
2.6.3 格式输出函数printf 54
2.6.4 格式输入函数scanf 56
2.7 函数 57
2.7.1 函数的定义 57
2.7.2 函数的调用 58
2.7.3 变量的存储类别 59
2.8 数组 62
2.8.1 一维数组的定义和使用 63
2.8.2 二维数组的定义和使用 64
2.8.3 字符数组和字符串 65
2.8.4 常用字符串处理函数 66
2.9 指针 69
2.9.1 地址和指针 69
2.9.2 指针的定义和使用 70
2.9.3 数组与指针 71
2.9.4 字符串与指针 72
2.9.5 指向函数的指针 72
2.10 结构体和共用体 73
2.10.1 定义和引用结构体 73
2.10.2 结构体数组 74
2.10.3 指向结构体的指针 74
2.10.4 共用体 75
2.10.5 使用typedef定义类型 77
2.11 链表 77
2.11.1 链表概述 77
2.11.2 建立动态单向链表 78
2.11.3 单向链表的输出 80
2.11.4 对单向链表的删除操作 80
2.11.5 对单向链表的插入操作 81
2.11.6 循环链表 82
2.11.7 双向链表 82
2.12 位运算符和位运算 83
2.12.1 “按位与”运算符(&) 84
2.12.2 “按位或”运算符(|) 84
2.12.3 “取反”运算符(~) 84
2.12.4 “异或”运算符(^) 84
2.12.5 移位运算符(<<和>>) 85
2.12.6 位域 85
2.13 C语言预处理命令 86
2.13.1 宏定义 86
2.13.2 文件包含 87
2.13.3 条件编译 88
2.13.4 #error等其他常用预处理命令 89
2.14 本章小结 89
实战演练 89
第3章 vi与Emacs编辑器 91
3.1 vi的使用 92
3.1.1 启动与退出vi 92
3.1.2 vi的命令行模式 93
3.1.3 vi的插入模式 96
3.1.4 vi的底行模式 96
3.2 vi使用实例 97
3.3 Emacs的使用 100
3.3.1 启动与退出Emacs 101
3.3.2 Emacs下的基本操作 102
3.4 Emacs使用实例 107
3.5 本章小结 109
实战演练 109
第4章 gcc编译器与gdb调试器 110
4.1 gcc编译器简介 111
4.2 如何使用gcc 112
4.2.1 gcc编译初步 112
4.2.2 警告提示功能 114
4.2.3 优化gcc 116
4.2.4 连接库 119
4.2.5 同时编译多个源程序 120
4.2.6 管道 120
4.2.7 调试选项 121
4.3 gdb调试器 122
4.3.1 gdb简介 122
4.3.2 gdb常用命令 123
4.3.3 gdb调试初步 124
4.4 gdb的使用详解 126
4.4.1 调用gdb 127
4.4.2 使用断点 127
4.4.3 查看运行时数据 129
4.4.4 查看源程序 133
4.4.5 改变程序的执行 135
4.5 xxgdb调试器简介 138
4.6 本章小结 139
实战演练 139
第5章 make的使用和Makefile的编写 141
5.1 什么是make 142
5.1.1 make机制概述 142
5.1.2 make与Makefile的关系 144
5.2 Makefile的书写规则 147
5.2.1 Makefile的基本语法规则 148
5.2.2 在规则中使用通配符 149
5.2.3 伪目标 149
5.2.4 多目标 151
5.2.5 自动生成依赖性 151
5.3 Makefile的命令 152
5.4 变量 154
5.4.1 变量的基础 154
5.4.2 赋值变量 154
5.4.3 define关键字 156
5.4.4 override指示符 156
5.4.5 目标变量和模式变量 157
5.5 常用函数调用 158
5.5.1 字符串处理函数 158
5.5.2 文件名操作函数 162
5.5.3 循环函数 164
5.5.4 条件判断函数 165
5.5.5 其他常用函数 166
5.6 隐式规则 168
5.6.1 隐式规则举例 168
5.6.2 隐式规则中的变量 169
5.6.3 使用模式规则 170
5.7 本章小结 173
实战演练 173
第2部分 提高篇
第6章 文件I/O操作 174
6.1 Linux文件系统简介 175
6.1.1 Linux的文件系统结构 175
6.1.2 文件类型 176
6.1.3 文件访问权限 179
6.2 基于文件描述符的I/O操作 179
6.2.1 文件描述符 180
6.2.2 标准输入、标准输出和标准出错 180
6.2.3 文件重定向 181
6.2.4 文件的创建、打开与关闭 182
6.2.5 文件的定位 186
6.2.6 文件的读写 188
6.3 文件的属性操作 192
6.3.1 改变文件访问权限 192
6.3.2 改变文件所有者 193
6.3.3 重命名 193
6.3.4 修改文件长度 194
6.4 文件的其他操作 195
6.4.1 stat、fstat和lstat函数 195
6.4.2 p和p2函数 196
6.4.3 fcntl函数 197
6.4.4 sync和fsync函数 197
6.5 特殊文件的操作 198
6.5.1 目录文件的操作 198
6.5.2 链接文件的操作 201
6.5.3 管道文件的操作 204
6.5.4 设备文件 204
6.6 本章小结 205
实战演练 205
第7章 基于流的I/O操作 206
7.1 流与缓存 207
7.1.1 流和FILE对象 207
7.1.2 标准输入、标准输出和标准出错 207
7.1.3 缓存 207
7.1.4 对缓存的操作 210
7.2 流的打开与关闭 212
7.2.1 流的打开 212
7.2.2 流的关闭 214
7.2.3 流关闭前的工作 216
7.3 流的读写 216
7.3.1 基于字符的I/O 217
7.3.2 基于行的I/O 220
7.3.3 直接I/O 222
7.3.4 格式化I/O 224
7.4 本章小结 226
实战演练 227
第8章 进程控制 228
8.1 进程的基本概念 229
8.1.1 Linux进程简介 229
8.1.2 进程与作业 230
8.1.3 进程标识 230
8.2 进程控制的相关函数 232
8.2.1 fork和vfork函数 232
8.2.2 exec函数 237
8.2.3 exit和_exit函数 242
8.2.4 wait和waitpid函数 245
8.2.5 进程的一生 251
8.2.6 用户ID和组ID 251
8.2.7 system函数 253
8.3 多个进程间的关系 255
8.3.1 进程组 255
8.3.2 会话期 256
8.3.3 控制终端 257
8.4 本章小结 259
实战演练 259
第9章 信号 260
9.1 Linux信号简介 261
9.1.1 信号的基本概念 261
9.1.2 信号处理机制 265
9.2 信号操作的相关函数 267
9.2.1 信号的处理 267
9.2.2 信号的发送 274
9.2.3 信号的阻塞 282
9.2.4 计时器与信号 284
9.3 本章小结 286
实战演练 287
第10章 进程间通信 288
10.1 进程间通信简介 289
10.2 管道 290
10.2.1 管道的概念 290
10.2.2 管道的创建与关闭 291
10.2.3 管道的读写 292
10.3 命名管道 297
10.3.1 命名管道的概念 297
10.3.2 命名管道的创建 297
10.3.3 命名管道的读写 299
10.4 消息队列 303
10.4.1 消息队列的概念 303
10.4.2 消息队列的创建与打开 305
10.4.3 消息队列的读写 306
10.4.4 获得或设置消息队列属性 308
10.5 共享内存 312
10.5.1 共享内存的概念 312
10.5.2 共享内存的相关操作 313
10.6 信号量 318
10.6.1 信号量的概念 319
10.6.2 信号量集的相关操作 320
10.7 本章小结 325
实战演练 326
第11章 网络编程 327
11.1 网络编程的基础知识 328
11.1.1 计算机网络体系结构 328
11.1.2 传输控制协议TCP 333
11.1.3 用户数据报协议UDP 335
11.1.4 客户机/服务器模式 336
11.2 套接口编程基础 336
11.2.1 什么是套接口 337
11.2.2 端口号的概念 338
11.2.3 套接口的数据结构 338
11.2.4 基本函数 340
11.3 TCP套接口编程 343
11.3.1 TCP套接口通信工作流程 343
11.3.2 TCP套接口Client/Server程序实例 356
11.4 UDP套接口编程 360
11.4.1 UDP套接口通信工作流程 360
11.4.2 UDP套接口Client/Server程序实例 362
11.5 原始套接口编程 365
11.5.1 原始套接口的创建 365
11.5.2 原始套接口程序实例 365
11.6 本章小结 376
实战演练 376
第12章 Linux图形界面编程 377
12.1 Linux下的图形界面编程简介 378
12.1.1 Qt简介 378
12.1.2 GTK+简介 378
12.2 界面基本元件 381
12.2.1 一个简单的例子 381
12.2.2 窗口 383
12.2.3 标签 385
12.2.4 按钮 386
12.2.5 文本框 387
12.3 界面布局元件 389
12.3.1 表格 390
12.3.2 框 393
12.3.3 窗格 395
12.4 其他常用元件 398
12.4.1 进度条、微调按钮、组合框 398
12.4.2 单选按钮、复选按钮 402
12.4.3 下拉菜单 404
12.5 信号与回调函数 406
12.6 本章小结 409
实战演练 409
第3部分 实战篇
第13章 设计Linux下的计算器 411
13.1 软件功能分析 412
13.2 程序模块的划分 413
13.3 软件的具体实现 415
13.3.1 头文件 415
13.3.2 十六进制界面显示函数 416
13.3.3 十进制界面显示函数 417
13.3.4 八进制界面显示函数 418
13.3.5 二进制界面显示函数 419
13.3.6 进制间转换函数 420
13.3.7 信号处理模块 423
13.3.8 主函数 432
13.4 软件使用效果演示 438
13.5 本章小结 439
第14章 Linux平台下聊天软件的设计 440
14.1 软件功能概述 441
14.1.1 服务器端功能需求 441
14.1.2 客户端功能需求 442
14.1.3 错误处理需求 442
14.2 Glade集成开发工具简介 443
14.3 软件功能模块划分 444
14.3.1 服务器功能模块划分 444
14.3.2 客户端功能模块划分 445
14.3.3 消息标识的定义 445
14.3.4 消息结构体的设计 446
14.4 服务器程序的具体实现 447
14.4.1 服务器消息处理流程 447
14.4.2 服务器主要函数和变量 448
14.4.3 服务器消息处理模块的设计与实现 449
14.4.4 服务器数据存储的方法 450
14.4.5 用户注册流程 450
14.5 客户端程序的具体实现 451
14.5.1 客户端操作流程 451
14.5.2 客户端发送和接收消息流程 451
14.5.3 客户端主要函数和变量 452
14.5.4 客户端功能模块的设计与实现 453
14.6 聊天软件使用效果演示 455
14.7 本章小结 459
第15章 Linux远程管理工具的设计 460
15.1 软件功能概述 461
15.1.1 Webmin简介 461
15.1.2 软件总体设计 461
15.2 服务器端程序设计 463
15.2.1 服务器端工作流程 463
15.2.2 系统用户管理操作 464
15.2.3 系统用户组的管理操作 466
15.2.4 系统服务启动管理 468
15.2.5 DNS管理操作 469
15.2.6 Apache服务管理操作 471
15.2.7 FTP服务管理操作 474
15.3 客户端程序 475
15.3.1 连接界面 475
15.3.2 主界面 477
15.4 本章小结 479
第16章 Linux下简易防火墙软件的设计 480
16.1 Netfilter基础 481
16.1.1 什么是Netfilter 481
16.1.2 Netfilter的HOOK机制 482
16.1.3 HOOK的调用 485
16.1.4 HOOK的实现 486
16.1.5 IPTables简介 488
16.1.6 Netfilter可以实现的控制功能 489
16.2 软件设计概述 491
16.2.1 软件整体框架 491
16.2.2 管理端的设计 492
16.2.3 控制端的设计 493
16.3 用Netfilter设计控制端功能模块 495
16.3.1 ICMP管理控制模块 495
16.3.2 FTP管理控制模块 497
16.3.3 HTTP管理控制模块 499
16.3.4 模块的编译、加载与卸载 499
16.4 软件功能测试 501
16.5 本章小结 503
第17章 基于Linux的嵌入式家庭网关远程交互操作平台的设计 504
17.1 嵌入式技术简介 505
17.1.1 嵌入式系统的概念 505
17.1.2 嵌入式操作系统 506
17.1.3 嵌入式处理器 507
17.2 家庭网关的概念及其网络体系结构 509
17.2.1 智能家庭网络的概念 509
17.2.2 家庭网关的远程交互操作技术简介 510
17.2.3 嵌入式家庭网关的网络体系结构 510
17.3 嵌入式家庭网关的开发平台 511
17.3.1 S3C2410微处理器简介 511
17.3.2 交叉编译环境的建立 513
17.4 远程交互平台的设计 515
17.4.1 应用软件的开发模式 515
17.4.2 嵌入式Web服务器 516
17.4.3 通用网关接口CGI 519
17.5 Linux下软件模块的具体实现 520
17.5.1 登录验证模块 521
17.5.2 串口通信模块 521
17.5.3 中央空调控制模块 522
17.5.4 智能水表数据采集模块 528
17.5.5 试验结果 528
17.6 本章小结 529
B. linux操作系统上c语言编程入门怎么解决
Linux程序设计入门--进程介绍
Linux下进程的创建
前言:
这篇文章是用来介绍在Linux下和进程相关的各个概念.我们将会学到:
进程的概念
进程的身份
进程的创建
守护进程的创建
----------------------------------------
----
1。进程的概念
Linux操作系统是面向多用户的.在同一时间可以有许多用户向操作系统发出各种命
令.那么操作系统是怎么实现多用户的环境呢? 在现代的操作系统里面,都有程序和进程
的概念.那么什么是程序,什么是进程呢? 通俗的讲程序是一个包含可以执行代码的文件
,是一个静态的文件.而进程是一个开始执行但是还没有结束的程序的实例.就是可执行文
件的具体实现. 一个程序可能有许多进程,而每一个进程又可以有许多子进程.依次循环
下去,而产生子孙进程. 当程序被系统调用到内存以后,系统会给程序分配一定的资源(内
存,设备等等)然后进行一系列的复杂操作,使程序变成进程以供系统调用.在系统里面只
有进程没有程序,为了区分各个不同的进程,系统给每一个进程分配了一个ID(就象我们的
身份证)以便识别. 为了充分的利用资源,系统还对进程区分了不同的状态.将进程分为新
建,运行,阻塞,就绪和完成五个状态. 新建表示进程正在被创建,运行是进程正在运行,阻
塞是进程正在等待某一个事件发生,就绪是表示系统正在等待CPU来执行命令,而完成表示
进程已经结束了系统正在回收资源. 关于进程五个状态的详细解说我们可以看《操作系
统》上面有详细的解说。
2。进程的标志
上面我们知道了进程都有一个ID,那么我们怎么得到进程的ID呢?系统调用getpid可
以得到进程的ID,而getppid可以得到父进程(创建调用该函数进程的进程)的ID.
#include <unistd>
pid_t getpid(void);
pid_t getppid(void);
进程是为程序服务的,而程序是为了用户服务的.系统为了找到进程的用户名,还为进程和
用户建立联系.这个用户称为进程的所有者.相应的每一个用户也有一个用户ID.通过系统
调用getuid可以得到进程的所有者的ID.由于进程要用到一些资源,而Linux对系统资源是
进行保护的,为了获取一定资源进程还有一个有效用户ID.这个ID和系统的资源使用有关
,涉及到进程的权限. 通过系统调用geteuid我们可以得到进程的有效用户ID. 和用户ID
相对应进程还有一个组ID和有效组ID系统调用getgid和getegid可以分别得到组ID和有效
组ID
#include <unistd>
#include <sys/types.h>
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
git_t getegid(void);
有时候我们还会对用户的其他信息感兴趣(登录名等等),这个时候我们可以调用getpwui
d来得到.
struct passwd {
char *pw_name; /* 登录名称 */
char *pw_passwd; /* 登录口令 */
uid_t pw_uid; /* 用户ID */
gid_t pw_gid; /* 用户组ID */
char *pw_gecos; /* 用户的真名 */
char *pw_dir; /* 用户的目录 */
char *pw_shell; /* 用户的SHELL */
};
#include <pwd.h>
#include <sys/types.h>
struct passwd *getpwuid(uid_t uid);
下面我们学习一个实例来实践一下上面我们所学习的几个函数:
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc,char **argv)
{
pid_t my_pid,parent_pid;
uid_t my_uid,my_euid;
gid_t my_gid,my_egid;
struct passwd *my_info;
my_pid=getpid();
parent_pid=getppid();
my_uid=getuid();
my_euid=geteuid();
my_gid=getgid();
my_egid=getegid();
my_info=getpwuid(my_uid);
printf("Process ID:%ld/n",my_pid);
printf("Parent ID:%ld/n",parent_pid);
printf("User ID:%ld/n",my_uid);
printf("Effective User ID:%ld/n",my_euid);
printf("Group ID:%ld/n",my_gid);
printf("Effective Group ID:%ld/n",my_egid):
if(my_info)
{
printf("My Login Name:%s/n" ,my_info->pw_name);
printf("My Password :%s/n" ,my_info->pw_passwd);
printf("My User ID :%ld/n",my_info->pw_uid);
printf("My Group ID :%ld/n",my_info->pw_gid);
printf("My Real Name:%s/n" ,my_info->pw_gecos);
printf("My Home Dir :%s/n", my_info->pw_dir);
printf("My Work Shell:%s/n", my_info->pw_shell);
}
}
3。进程的创建
创建一个进程的系统调用很简单.我们只要调用fork函数就可以了.
#include <unistd.h>
pid_t fork();
当一个进程调用了fork以后,系统会创建一个子进程.这个子进程和父进程不同的地方只
有他的进程ID和父进程ID,其他的都是一样.就象符进程克隆(clone)自己一样.当然创建
两个一模一样的进程是没有意义的.为了区分父进程和子进程,我们必须跟踪fork的返回
值. 当fork掉用失败的时候(内存不足或者是用户的最大进程数已到)fork返回-1,否则f
ork的返回值有重要的作用.对于父进程fork返回子进程的ID,而对于fork子进程返回0.我
们就是根据这个返回值来区分父子进程的. 父进程为什么要创建子进程呢?前面我们已经
说过了Linux是一个多用户操作系统,在同一时间会有许多的用户在争夺系统的资源.有时
进程为了早一点完成任务就创建子进程来争夺资源. 一旦子进程被创建,父子进程一起从
fork处继续执行,相互竞争系统的资源.有时候我们希望子进程继续执行,而父进程阻塞直
到子进程完成任务.这个时候我们可以调用wait或者waitpid系统调用.
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid,int *stat_loc,int options);
wait系统调用会使父进程阻塞直到一个子进程结束或者是父进程接受到了一个信号.如果
没有父进程没有子进程或者他的子进程已经结束了wait回立即返回.成功时(因一个子进
程结束)wait将返回子进程的ID,否则返回-1,并设置全局变量errno.stat_loc是子进程的
退出状态.子进程调用exit,_exit 或者是return来设置这个值. 为了得到这个值Linux定
义了几个宏来测试这个返回值.
WIFEXITED:判断子进程退出值是非0
WEXITSTATUS:判断子进程的退出值(当子进程退出时非0).
WIFSIGNALED:子进程由于有没有获得的信号而退出.
WTERMSIG:子进程没有获得的信号号(在WIFSIGNALED为真时才有意义).
waitpid等待指定的子进程直到子进程返回.如果pid为正值则等待指定的进程(pid).如果
为0则等待任何一个组ID和调用者的组ID相同的进程.为-1时等同于wait调用.小于-1时等
待任何一个组ID等于pid绝对值的进程. stat_loc和wait的意义一样. options可以决定
父进程的状态.可以取两个值 WNOHANG:父进程立即返回当没有子进程存在时. WUNTACHE
D:当子进程结束时waitpid返回,但是子进程的退出状态不可得到.
父进程创建子进程后,子进程一般要执行不同的程序.为了调用系统程序,我们可以使用系
统调用exec族调用.exec族调用有着5个函数.
#include <unistd.h>
int execl(const char *path,const char *arg,...);
int execlp(const char *file,const char *arg,...);
int execle(const char *path,const char *arg,...);
int execv(const char *path,char *const argv[]);
int execvp(const char *file,char *const argv[]):
exec族调用可以执行给定程序.关于exec族调用的详细解说可以参考系统手册(man exec
l). 下面我们来学习一个实例.注意编译的时候要加 -lm以便连接数学函数库.
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <math.h>
void main(void)
{
pid_t child;
int status;
printf("This will demostrate how to get child status/n");
if((child=fork())==-1)
{
printf("Fork Error :%s/n",strerror(errno));
exit(1);
}
else if(child==0)
{
int i;
printf("I am the child:%ld/n",getpid());
for(i=0;i<1000000;i++) sin(i);
i=5;
printf("I exit with %d/n",i);
exit(i);
}
while(((child=wait(&status))==-1)&(errno==EINTR));
if(child==-1)
printf("Wait Error:%s/n",strerror(errno));
else if(!status)
printf("Child %ld terminated normally return status is zero/n",
child);
else if(WIFEXITED(status))
printf("Child %ld terminated normally return status is %d/n",
child,WEXITSTATUS(status));
else if(WIFSIGNALED(status))
printf("Child %ld terminated e to signal %d znot caught/n",
child,WTERMSIG(status));
}
strerror函数会返回一个指定的错误号的错误信息的字符串.
4。守护进程的创建
如果你在DOS时代编写过程序,那么你也许知道在DOS下为了编写一个常驻内存的程序
我们要编写多少代码了.相反如果在Linux下编写一个"常驻内存"的程序却是很容易的.我
们只要几行代码就可以做到. 实际上由于Linux是多任务操作系统,我们就是不编写代码
也可以把一个程序放到后台去执行的.我们只要在命令后面加上&符号SHELL就会把我们的
程序放到后台去运行的. 这里我们"开发"一个后台检查邮件的程序.这个程序每个一个指
定的时间回去检查我们的邮箱,如果发现我们有邮件了,会不断的报警(通过机箱上的小喇
叭来发出声音). 后面有这个函数的加强版本加强版本
后台进程的创建思想: 首先父进程创建一个子进程.然后子进程杀死父进程(是不是很无
情?). 信号处理所有的工作由子进程来处理.
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
/* Linux 的默任个人的邮箱地址是 /var/spool/mail/用户的登录名 */
#define MAIL "/var/spool/mail/hoyt"
/* 睡眠10秒钟 */
#define SLEEP_TIME 10
main(void)
{
pid_t child;
if((child=fork())==-1)
{
printf("Fork Error:%s/n",strerror(errno));
exit(1);
}
else if(child>0)
while(1);
if(kill(getppid(),SIGTERM)==-1)
{
printf("Kill Parent Error:%s/n",strerror(errno));
exit(1);
}
{
int mailfd;
while(1)
{
if((mailfd=open(MAIL,O_RDONLY))!=-1)
{
fprintf(stderr,"%s","7");
close(mailfd);
}
sleep(SLEEP_TIME);
}
}
}
你可以在默认的路径下创建你的邮箱文件,然后测试一下这个程序.当然这个程序还有很
多地方要改善的.我们后面会对这个小程序改善的,再看我的改善之前你可以尝试自己改
善一下.比如让用户指定邮相的路径和睡眠时间等等.相信自己可以做到的.动手吧,勇敢
的探险者.
好了进程一节的内容我们就先学到这里了.进程是一个非常重要的概念,许多的程序都会
用子进程.创建一个子进程是每一个程序员的基本要求!
C. Linux系统下的C语言开发都需要学些什么
C语言在Linux上的应用主要是三种,Server端坦伏应用、内核应用和嵌入式应用。Server端应用就写各种服务器,了解各种通讯协议,在具体实践中按项目需要学习。内核应用一般是数据包处理和驱动开发,知睁猜识点和嵌入式开发有重叠。嵌入式开发是编写非x86的异构平台上的应用,通过交叉环境,在PC上开发,在目标芯片上运行。Linux开发是嵌入式开发最常用的一种。通过学习嵌入式Linux开发,能掌握交叉编悉信型译环境的搭建和使用、Linux内核编译和剪裁、硬件驱动及应用程序开发等。学习方法是买套嵌入式开发板,最好有配套的视频教程,按教程一步一步学习。C语言很枯燥,没有UI,如果单纯的按书本学习编程很难坚持下去,只有跟硬件结合才能提高趣味性。
D. 怎样学习在linux操作系统下用C语言编程
这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将会学到以下内容:
源程序编译
Makefile的编写
程序库的链接
程序的调试
头文件和系统求助
--------------------------------------------------------------------------------
1.源程序的编译
在Linux下面,如果要编译一个C语言源程序,我们要使用GNU的gcc编译器. 下面我们以一个实例来说明如何使用gcc编译器.
假设我们有下面一个非常简单的源程序(hello.c):
int main(int argc,char **argv)
{
printf("Hello Linux\n");
}
要编译这个程序,我们只要在命令行下执行:
gcc -o hello hello.c
gcc 编译器就会为我们生成一个hello的可执行文件.执行./hello就可以看到程序的输出结果了.命令行中
gcc表示我们是用gcc来编译我们的源程序,-o 选项表示我们要求编译器给我们输出的可执行文件名为hello
而hello.c是我们的源程序文件. gcc编译器有许多选项,一般来说我们只要知道其中的几个就够了. -o选项我们已经知道了,表示我们要求输出的可执行文件名.
-c选项表示我们只要求编译器输出目标代码,而不必要输出可执行文件. -g选项表示我们要求编译器在编译的时候提供我们以后对程序进行调试的信息. 知道了这三个选项,我们就可以编译我们自己所写的简单的源程序了,如果你想要知道更多的选项,可以查看gcc的帮助文档,那里有着许多对其它选项的详细说明.
2.Makefile的编写
假设我们有下面这样的一个程序,源代码如下:
/* main.c */
#include "mytool1.h"
#include "mytool2.h"
int main(int argc,char **argv)
{
mytool1_print("hello");
mytool2_print("hello");
}
/* mytool1.h */
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char *print_str);
#endif
/* mytool1.c */
#include "mytool1.h"
void mytool1_print(char *print_str)
{
printf("This is mytool1 print %s\n",print_str);
}
/* mytool2.h */
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
#endif
/* mytool2.c */
#include "mytool2.h"
void mytool2_print(char *print_str)
{
printf("This is mytool2 print %s\n",print_str);
}
当然由于这个程序是很短的我们可以这样来编译
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
这样的话我们也可以产生main程序,而且也不时很麻烦.但是如果我们考虑一下如果有一天我们修改了其中的一个文件(比如说mytool1.c)
那么我们难道还要重新输入上面的命令?也许你会说,这个很容易解决啊,我写一个SHELL脚本,让她帮我去完成不就可以了.是的对于这个程序来说,是可以
起到作用的.但是当我们把事情想的更复杂一点,如果我们的程序有几百个源程序的时候,难道也要编译器重新一个一个的去编译? 为此,聪明的程序员们想出了一个很好的工具来做这件事情,这就是make.我们只要执行以下make,就可以把上面的问题解决掉.在我们执行
make之前,我们要先编写一个非常重要的文件.--Makefile.对于上面的那个程序来说,可能的一个Makefile的文件是: # 这是上面那个程序的Makefile文件
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
有了这个Makefile文件,不过我们什么时候修改了源程序当中的什么文件,我们只要执行make命令,我们的编译器都只会去编译和我们修改的文件有关的文件,其它的文件她连理都不想去理的.
下面我们学习Makefile是如何编写的.
在Makefile中也#开始的行都是注释行.Makefile中最重要的是描述文件的依赖关系的说明.一般的格式是:
target: components
TAB rule
第一行表示的是依赖关系.第二行是规则.
比如说我们上面的那个Makefile文件的第二行
main:main.o mytool1.o mytool2.o
表示我们的目标(target)main的依赖对象(components)是main.o mytool1.o mytool2.o
当倚赖的对象在目标修改后修改的话,就要去执行规则一行所指定的命令.就象我们的上面那个Makefile第三行所说的一样要执行 gcc -o
main main.o mytool1.o mytool2.o 注意规则一行中的TAB表示那里是一个TAB键 Makefile有三个非常有用的变量.分别是$@,$^,$
int main(int argc,char **argv)
{
double value;
printf("Value:%f\n",value);
}
这个程序相当简单,但是当我们用 gcc -o temp temp.c 编译时会出现下面所示的错误.
/tmp/cc33Ky.o: In function `main':
/tmp/cc33Ky.o(.text+0xe): undefined reference to `log'
collect2: ld returned 1 exit status
出现这个错误是因为编译器找不到log的具体实现.虽然我们包括了正确的头文件,但是我们在编译的时候还是要连接确定的库.在Linux下,为了
使用数学函数,我们必须和数学库连接,为此我们要加入 -lm 选项. gcc -o temp temp.c
-lm这样才能够正确的编译.也许有人要问,前面我们用printf函数的时候怎么没有连接库呢?是这样的,对于一些常用的函数的实现,gcc编译器会自
动去连接一些常用库,这样我们就没有必要自己去指定了. 有时候我们在编译程序的时候还要指定库的路径,这个时候我们要用到编译器的
-L选项指定路径.比如说我们有一个库在 /home/hoyt/mylib下,这样我们编译的时候还要加上
-L/home/hoyt/mylib.对于一些标准库来说,我们没有必要指出路径.只要它们在起缺省库的路径下就可以了.系统的缺省库的路径/lib
/usr/lib /usr/local/lib 在这三个路径下面的库,我们可以不指定路径. 还有一个问题,有时候我们使用了某个函数,但是我们不知道库的名字,这个时候怎么办呢?很抱歉,对于这个问题我也不知道答案,我只有一个傻办
法.首先,我到标准库路径下面去找看看有没有和我用的函数相关的库,我就这样找到了线程(thread)函数的库文件(libpthread.a).
当然,如果找不到,只有一个笨方法.比如我要找sin这个函数所在的库. 就只好用 nm -o /lib/*.so|grep
sin>~/sin 命令,然后看~/sin文件,到那里面去找了.
在sin文件当中,我会找到这样的一行libm-2.1.2.so:00009fa0 W sin 这样我就知道了sin在
libm-2.1.2.so库里面,我用 -lm选项就可以了(去掉前面的lib和后面的版本标志,就剩下m了所以是 -lm).
如果你知道怎么找,请赶快告诉我,我回非常感激的.谢谢! 4.程序的调试
我们编写的程序不太可能一次性就会成功的,在我们的程序当中,会出现许许多多我们想不到的错误,这个时候我们就要对我们的程序进行调试了.
最常用的调试软件是gdb.如果你想在图形界面下调试程序,那么你现在可以选择xxgdb.记得要在编译的时候加入
-g选项.关于gdb的使用可以看gdb的帮助文件.由于我没有用过这个软件,所以我也不能够说出如何使用.
不过我不喜欢用gdb.跟踪一个程序是很烦的事情,我一般用在程序当中输出中间变量的值来调试程序的.当然你可以选择自己的办法,没有必要去学别人的.现
在有了许多IDE环境,里面已经自己带了调试器了.你可以选择几个试一试找出自己喜欢的一个用.
5.头文件和系统求助
有时候我们只知道一个函数的大概形式,不记得确切的表达式,或者是不记得着函数在那个头文件进行了说明.这个时候我们可以求助系统.
比如说我们想知道fread这个函数的确切形式,我们只要执行 man fread
系统就会输出着函数的详细解释的.和这个函数所在的头文件说明了. 如果我们要write这个函数的说明,当我们执行man
write时,输出的结果却不是我们所需要的.
因为我们要的是write这个函数的说明,可是出来的却是write这个命令的说明.为了得到write的函数说明我们要用 man 2 write.
2表示我们用的write这个函数是系统调用函数,还有一个我们常用的是3表示函数是C的库函数. 记住不管什么时候,man都是我们的最好助手.
--------------------------------------------------------------------------------
好了,这一章就讲这么多了,有了这些知识我们就可以进入激动人心的Linux下的C程序探险活动.
不积跬步,无以至千里!
E. Linux环境下C开发_linux搭建c语言开发环境
一:C语言嵌入式Linux工程师的学习需要具备一定的C语言基础,C语言是嵌入式领域最重要也是最主要的编程语言,通过大量编程实例重点理解C语言的基础编程以及高级编程知识。包括:基本数据类型、数组、指针、结构体、链表、文件操作、队列、栈等。
二:Linux基础Linux操作系统的概念、安装方法,详细了解Linux下的目录结构、基本命令、编辑器VI,编译器GCC,调试器GDB和Make项目管理工具,ShellMakefile脚本编写等知识,嵌入式开发环境的搭建。
三:Linux系统编程重点学习标准I/O库,Linux多任务编程中的多进程和多线程,以及进程间通信(pipe、FIFO、消息队列、共享内存、signal、信号量等),同步与互斥对共享资源访问控制等重要知识,主要提升对Linux应用开发的理解和代码调试的能力。
四:Linux网络编程计算机网络在嵌入式Linux系统应用开发过程中使用非常广泛,通过Linux网络发展、TCP/IP协议、socket编程、TCP网络编程、UDP网络编程、Web编程开发等方面入手,全面了解Linux网络应用程序开发。重点学习网络编程相关API,熟练掌握TCP协议服务器的编程方法和并发服务器的实现,了解HTTP协议及其实现方法,熟悉UDP广播、多播的原理及编程方法,掌握混合C/S架构网络通信系统的设计,熟悉HTML,Javascript等Web编程技术及实现方法。
五:数据结构与算法数据结构及算法在嵌入式底层驱动、通信协议、及各种引擎开发中会得到大量应用,对其掌握的好坏直接影响程序的效率、简洁及健壮旅瞎性。此阶段的学习要重点理解数据结构与算法的基础内容,包括顺序表、链表、队列、栈、树、图、哈希表、各种查找排序算法等应用及其C语言实现过程。
六:C、QTC是Linux应用开发主要语言之一,本阶段重点掌握面向对象编程的基本思想以及C的重要内容。图形界面编程是嵌入式开发中非常重要的一个环节。由于QT具有跨平台、面向对象、丰富API、支持2D/3D渲染、支持XML、多国语等强大功能,在嵌入式领域的GUI开发中得到了广范的应用,在本阶段通过基于QT图形库的学习使学员可以熟练编写GUI程序,并移植QT应用程序到Cortex-A8平台。包括IDE使用、QT部件及布局管理器、信息与槽机制的应用、鼠标、键盘及绘图事件处理及文件处理的应用。
七:CortexA8、Linux平台开发通过基于ARMCortex-A8处理s5pv210了解芯片手册的基本阅读技巧,掌握s5pv210系统资源、时钟控制器、电源管理、异常中断控制器、nandflash控制器等模块,为底层平台搭建做好准备。Linux平台包括内核裁减、内核移植、交叉编译、GNU工具使用、内核调试、Bootloader介绍、制作与原理分析、根文件系统制作以及向内核中添加自己的模块,并在s5pv210实验平台上运行自己制作的Linux系统,集成部署Linux系统整个流程。同时了解Android操作系统开发流程。Android系统是基于Linux平台的开源操作系统,该平台由操作系统、中间件、用户界面和应用软件组成,是首个为移动终端打造的真正开放和完整的移动软件,目前它的应用不再局限于移动终端,还包括数据电视、机顶盒、PDA等消费类电子产品。
八:驱动开发拆颤空驱动程序设计是嵌入式Linux开发工作中重要的一部分,也是比较困难的一部分。本阶洞租段的学习要熟悉Linux的内核机制、驱动程序与用户级应用程序的接口,掌握系统对设备的并发操作。熟悉所开发硬件的工作原理,具备ARM硬件接口的基础知识,熟悉ARMCortex-A8处理器s5pv210各资源、掌握Linux设备驱动原理框架,熟悉工程中常见Linux高级字符设备、块设备、网络设备、USB设备等驱动开发,在工作中能独立胜任底层驱动开发。
以上就是列出的关于一名合格嵌入式Linux开发工程师所必学的理论知识,其实,作为一个嵌入式开发人员,专业知识和项目经验同样重要,所以在我们的理论学习中也要有一定的项目实践,锻炼自己的项目开发能力。
F. 在linux里,c程序的编辑、编译、调试的详细步骤是什么
(1)用工具写好C程序...比如vi
(2)打开终端,进入你存放C语言代码的路径 例如: cd /opt/
(3)gcc a.c -o abc 意思是:把你的a.c编译成abc可执行文件
(4)在当前目录终端下 运行生成的abc,例如: ./abc 前面的.不要掉了
后面可以用gdb进行调试,你可以自己去学习...这是最基本的!!