ImageVerifierCode 换一换
格式:DOCX , 页数:26 ,大小:26.32KB ,
资源ID:4806185      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-4806185.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(学习《精通UNIX下C语言编程及项目实践》.docx)为本站会员(b****3)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

学习《精通UNIX下C语言编程及项目实践》.docx

1、学习精通UNIX下C语言编程及项目实践学习精通UNIX下C语言编程及项目实践1. 第一篇:起步篇 千里之行,始于足下。 一、 UNIX 初步 UNIX 自 1969 年诞生以来,已经发展为 System III & V 、 BSD 和 Linux 三大分支。 UniX 通过 shell 与用户交互,它是用户与系统间的界面。使用好 shell 对于学习使用 UNIX 来说是必须的。不需要你记住所有的命令,但基础的文件操作、目录操作及系统命令等却是必须的。 Vi 对于初学者是难点,不过只要通过一段时间的练习就能习惯;而且你会很快发现,它功能强大、更加灵活。这里不多说了:) 二、 编程套件 学习 U

2、NIX 对于初学者有几种选择。一种就是最直接的,在本机上安装 UNIX 系统,不如说 Linux 分支中的 Red Hat 等;一种是在 Windows 环境下使用虚拟机方式安装 UNIX 系统;另一种则是使用网络终端登录到网络环境中的某个 UNIX 系统中。 如果你相对黑洞洞的 UNIX 字符界面更喜欢舒适美观的 Windows 界面,那么推荐你选择第三种方式。开发套件包括:编辑器 UltraEdit 、网络终端 SecureCRT 或其他。 编译器就不用说了,自然是 cc ( gcc 或 xlc 系列)。这是 C 语言开发必不可少的。其中要注意 -I (加载头文件路径)、 -L (加载库文

3、件路径)及 -D (宏定义)参数的使用。 Make 工具使用。如何编写 makefile 是关键。后面项目中使用时会详细介绍。 Gdb 调试器。 Gdb 乃符号级调试工具,它控制程序的内部执行,利用断点设置、单步运行等手段,将程序的执行过程逐步展示在调试者目前。这种调试方式在短代码中可以发挥得很好。事实上,随着软件项目的扩大化、复杂化和分布化,很少有程序员直接通过 Gdb 等工具调试;使用日志记录调试方法比 Gdb 等调试工具更为便捷和广泛。 C 工具: lint 检查源代码是否正确, gprof 分析程序时间消费量, cflow 生成 C 语言流程图。 三、 库的使用 库分静态库和动态库两种

4、。 静态库的操作工具: ar 命令。 编写及使用静态库: (1) 设计库源码 pr1.c 和 pr2.c rootbillstone make_lib# cat pr1.c void print1() printf(This is the first lib src!n); rootbillstone make_lib# cat pr2.c void print2() printf(This is the second src lib!n); (2) 编译 .c 文件 billbillstone make_lib$ cc -O -c pr1.c pr2.c billbillstone make

5、_lib$ ls -l pr*.o -rw-rw-r- 1 bill bill 804 4 月 15 11:11 pr1.o -rw-rw-r- 1 bill bill 804 4 月 15 11:11 pr2.o (3) 链接静态库 为了在编译程序中正确找到库文件 , 静态库必须按照 libname.a 的规则命名 , 如下例中 name=pr. billbillstone make_lib$ ar -rsv libpr.a pr1.o pr2.o a - pr1.o a - pr2.o billbillstone make_lib$ ls -l *.a -rw-rw-r- 1 bill b

6、ill 1822 4 月 15 11:12 libpr.a billbillstone make_lib$ ar -t libpr.a pr1.o pr2.o (4) 调用库函数代码 main.c billbillstone make_lib$ cat main.c int main() print1(); print2(); return 0; (5) 编译链接选项 -L 及 -l 参数放在后面 . 其中 ,-L 加载库文件路径 ,-l 指明库文件名字 . billbillstone make_lib$ gcc -o main main.c -L./ -lpr billbillstone m

7、ake_lib$ ls -l main* -rwxrwxr-x 1 bill bill 11805 4 月 15 11:17 main -rw-rw-r- 1 bill bill 50 4 月 15 11:15 main.c (6) 执行目标程序 billbillstone make_lib$ ./main This is the first lib src! This is the second src lib! billbillstone make_lib$ 编写动态库 : (1) 设计库代码 billbillstone make_lib$ cat pr1.c int p = 2; voi

8、d print() printf(This is the first dll src!n); billbillstone make_lib$ (2) 生成动态库 billbillstone make_lib$ gcc -O -fpic -shared -o dl.so pr1.c billbillstone make_lib$ ls -l *.so -rwxrwxr-x 1 bill bill 6592 4 月 15 15:19 dl.so billbillstone make_lib$ 动态库的隐式调用 : 在编译调用库函数代码时指明动态库的位置及名字 , 看下面实例 billbillsto

9、ne make_lib$ cat main.c int main() print(); return 0; billbillstone make_lib$ gcc -o tdl main.c ./dl.so billbillstone make_lib$ ./tdl This is the first dll src! billbillstone make_lib$ 当动态库的位置活名字发生改变时 , 程序将无法正常运行 ; 而动态库取代静态库的好处之一则是通过更新动态库而随时升级库的内容 . 动态库的显式调用 : 显式调用动态库需要四个函数的支持 , 函数 dlopen 打开动态库 , 函数

10、 dlsym 获取动态库中对象基址 , 函数 dlerror 获取显式动态库操作中的错误信息 , 函数 doclose 关闭动态库 . billbillstone make_lib$ cat main.c #include int main() void *pHandle; void (*pFunc)(); / 指向函数的指针 int *p; pHandle = dlopen(./d1.so, RTLD_NOW); / 打开动态库 if(!pHandle) printf(Cant find d1.so n); exit(1); pFunc = (void (*)()dlsym(pHandle,

11、 print); / 获取库函数 print 的地址 if(pFunc) pFunc(); else printf(Cant find function printn); p = (int *)dlsym(pHandle, p); / 获取库变量 p 的地址 if(p) printf(p = %dn, *p); else printf(Cant find int pn); dlclose(pHandle); / 关闭动态库 return 0; billbillstone make_lib$ gcc -o tds main.c -ldl billbillstone make_lib$ ./tds

12、 This is the first dll src! p = 2 billbillstone make_lib$ 上面的程序 tds 显式调用了共享库 d1.so 中的函数 print 和变量 p. 第二篇 : 文件子系统 普天之下 , 莫非王土 ; 率土之滨 , 莫非王臣 . UNIX 之中 , 莫非文件 . 四、 文件系统结构 磁盘在使用前 , 需要分区和格式化 . 格式化操作将在磁盘分区中创建文件系统 , 它们将确定文件的存储方式和索引方法 , 确定磁盘空间分配和回收算法 . UNIX 文件系统的存储由 三级构成 , 其中目录存储了文件的层次结构 , 数据块存储了文件的具体信息 , i

13、 节点是连接文件层次结构与其数据内容的桥梁 . UNIX 文件系统将磁盘空间划分为一系列大小相同的块 , 划分为引导块、 超级块、 i 节点区和数据区四个部分 . 文件系统通过 i 节点对文件进行控制和管理 . 其中 , 每个文件对应一个 i 节点 , 每个 i 节点具有唯一的节点号 , 记录了文件的属性和内容在磁盘上的存储位置 . 但文件名并不记录在 i 节点里 , 而是存储在目录文件中 . 磁盘文件如何存储 ? 文件系统通过目录记载文件名及其对应的 i 节点编号 , 通过 i 节点记录文件的信息和内容 . 事实上 , i 节点直接记录的只是文件的属性 , 文件的具体内容存储在数据区的数据块

14、中 , i 节点中仅保留了一个 来记录文件内容存储的位置 . 由 13 个块号组成 , 每个块号占用 4 个字节 , 代表了数据区中的一个数据块编号 .UNIX 文件系统采用三级索引结构存储文件 , 它把 分为直接索引地址 , 一级索引地址 , 二级索引地址和三级索引地址等四个部分 . 其中前 10 项为直接索引地址 , 直接指向文件数据所在磁盘快的块号 . 第 11/12/13 项分别为一级 / 二级 / 三级索引地址 . 一级间接索引的含义在于其存储的并非文件数据所在磁盘块的块号 , 而是先指向一个 然后再指向具体磁盘块的块号 . 同理 , 二级 / 三级间接索引则是先间接指向了两次 才指

15、向具体磁盘块的块号 . 如果文件系统的数据块大小为 1kB, 每个 能够记录 256 个数据项 . 那么 , 直接索引能管辖 10 个数据块 , 而一级索引能管辖 1*256 个数据块 , 二级索引能管辖 1*256*256(65536) 个数据块 , 三级索引能管辖 1*256*256*256(16777216) 个数据块 . 例题 : 大小为 56000K 的文件 , 占用多少索引块空间 ? 答 : 因为 (10+256) 56000 tm_year+1900, mtime-tm_mon+1, mtime-tm_mday); 设计类似于 UNIX 命令 的程序 lsl, 主程序如下 bil

16、lbillstone Unix_study$ cat lsl.c #include #include #include #include int GetFileType(mode_t st_mode, char *resp); int GetFileMode(mode_t st_mode, char *resp); int GetFileOtherAttr(struct stat info, char *resp); int main(int argc, char *argv) struct stat info; char buf100, *p = buf; if(argc != 2) pri

17、ntf(Usage: lsl filenamen); return; memset(buf, 0, sizeof(buf); if(lstat(argv1, &info) = 0) p += GetFileType(info.st_mode, p); p += GetFileMode(info.st_mode, p); p += GetFileOtherAttr(info, p); printf(%s %sn, buf, argv1); else printf(Open file failed!n); return 0; 运行结果如下 : billbillstone Unix_study$ m

18、ake lsl cc lsl.c -o lsl billbillstone Unix_study$ ./lsl Usage: lsl filename billbillstone Unix_study$ ./lsl /etc/passwd -rw-r-r- 1 0 0 1639 20090328 /etc/passwd billbillstone Unix_study$ ls -l /etc/passwd -rw-r-r- 1 root root 1639 3 月 28 16:38 /etc/passwd 五 标准文件编程库 在 UNIX 的应用中 , 读写文件是最常见的任务 . 标准文件编程

19、库就是操作文件最简单的工具 . 标准编程函数库对文件流的输入输出操作非常灵活 , 我们既可以采用所见即所得的方式 , 以无格式方式读写文件 , 又可以对输入输出数据进行转化 , 以有格式方式读写文件 . 文件的无格式读写 无格式读写分三类 : 按字符读写 , 按行读写和按块读写 . 字符读写函数族 : #include int getc(FILE *stream); int fgetc(FILE *stream); int putc(int c, FILE *stream); int fputc(int c, FILE *stream); 函数 fgetc 的功能类似于 getc, 不同的是

20、, 它的执行速度远低于 getc. 行读写函数族 : #include char *gets(char *s); char *fgets(char *s, int n, FILE *stream); int puts(const char *s); int fputs(const char *s, FILE *stream); 函数 fgets 中加入了放溢出控制 , 应该优先选用 . 注意函数 fputs 把字符串 s( 不包括结束符 0) 写入文件流 stream 中 , 但不在输出换行符 n; 而函数 puts 则自动输出换行符 . 块读写函数族 : #include size_t fr

21、ead(void *ptr, size_t size, size_t nitems, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream); 函数 fread 和 fwrite 都不返回实际读写的字符个数 , 而返回的是实际读写的数据项数 . 块读写函数常用于保存和恢复内存数据 . 文件的格式化读写 文件格式化读写时能够自动转换的数据格式有 : 数据类型 、 精度 、 宽度 、 进制和标志等 , 而其一般格式为 % 标志 宽度 . 精度 类型 格式化输出函数族 #inclu

22、de int printf(const char *format, / * arg, */ . . .); int fprintf(FILE *stream, const char *format, / * arg, */ . . .); int sprintf(char *s, const char *format, / * arg, */ . . .); 在做字符串处理时应该善用 sprintf 函数 . 格式化输入函数族 #include int scanf(const char format, / * pointer, */ . . .); int fscanf(FILE *strea

23、m, const char format, / * pointer, */ . . .); int sscanf(const char *s, const char format, / * pointer, */ . . .); 二进制读写与文本读写 记得刚开始学习 C 语言的文件操作时 , 这是一个最让我疑惑的问题 . 我们都知道在调用 fopen 函数时需要指定操作类型 , 比如说文本写 r 和二进制写 rb. 那么它们究竟有何区别呢 ? 这要牵涉到两种存储方式 : 以字符为单位存储的文本文件和以二进制数据为单位存储的二进制文件 . 举个例子 : 我们通常阅读的 Readme.txt 文件

24、就是文本文件 , 该类型文件存储的是一个一个的字符 , 这些字符往往是可以打印的 ; 而我们的可执行程序 ( 比如 a.out) 则是二进制文件 , 该文件是不可读的 , 需要解析才能识别 . 那么在调用 fopen 函数时该如何选择呢 ? 如果你是先写入再从另外的地方读出 , 那么两种方式都可以 ; 只要按写入时的方式读取就可以了 . 但是 , 比起文本方式 , 二进制方式在保存信息时有着优势 : a) 加快了程序的执行速度 , 提高了软件的执行效率 . 内存中存储的都是二进制信息 , 直接以二进制方式与文件交互 , 可以免除二进制格式与文本格式之间的信息转换过程 . b) 节省了存储空间 . 一般来讲 , 二进制信息比文件信息占用更少的空间 , 比如 8 位的整型数采用文本方式存储至少需要 8 字节 , 而采用二进制存储只需一个整型即 4 个字节 . 编写变长参数函数 文件的格式化输入输出函数都支持变长参数 . 定义时 , 变长参数列表通过省略号 . 表示 , 因此函数定义格式为 : type 函数名 ( 参数 1, 参数 2, 参数 n, . . .); UNIX 的变长参数通过 va_list 对象实现 , 定义在文件 stdarg.h 中 , 变长参数的应用模板如下所示 : #include function(parmN, .)

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2