Linux程序设计实验指导书计算机应用系2012年11月实验一:Linux常用命令及编程环境1.实验相关知识简述Unix/Linux环境下使用C语言程序开发的项目主要经历设计、开发、调试、集成、部署和维护几个阶段。
目前典型的开发环境,主要使用vi、emacs、gedit等文字编辑工具完成源代码的编辑工作;通过指定不同的GCC编译器编译选项指定编译结果,根据编译器提示改正程序中的语法错误,最终生成符合目标要求的可执行二进制文件;当可执行文件执行结果与预期结果不一致时,使用GDB调试器跟踪程序执行过程,查看中间变量,改正源程序中存在的逻辑错误。
在大型项目管理中,由于文件较多,整个编译过程费时较长,安装、调试难度较大。
为解决手工管理效率低下的问题,引入Make工具,将项目编译、安装、维护等工作以脚本的形式组织在Makefile中,从而简化项目维护成本。
手工编写Makefile脚本难度较大且不利于统一规范,推荐使用Autotools工具集直接生成。
本实验仅设置手工编辑、编译Linux C源代码,生成可执行文件并调试。
GNU CC(简称为GCC)是GNU 项目中符合ANSI C 标准的编译系统,能够编译用C、C++和Object C 等语言编写的源程序。
GCC也可理解为一个工具集合,包含多个编译相关工具,如gcc编译C语言源程序,g++编译C++语言源程序,ld链接器等。
在编译C语言程序时,可直接使用gcc指令通过配置不同的参数选项达到指定GCC工具集的目的。
GCC的常用选项如表1.1所示表1.1 GCC常用选项功能选项描述与编译相关的GCC 选项-c 只是编译不链接,生成目标文件“.o”-S 只是编译不汇编,生成汇编代码-E 只进行预编译,不做其他处理-g 在可执行程序中包含标准调试信息-o file 把输出文件输出到file 里-v 打印出编译器内部编译各过程的命令行信息和编译器的版本-I dir 在头文件的搜索路径列表中添加dir 目录-L dir 在库文件的搜索路径列表中添加dir 目录-static 链接静态库-llibrary 连接名为library 的库文件报警与出错相关的-ansi 支持符合ANSI 标准的C 程序-pedantic 允许发出ANSI C 标准所列的全部警告信息GCC选项-pedantic-error 允许发出ANSI C 标准所列的全部错误信息-w 关闭所有告警-Wall 允许发出Gcc 提供的所有有用的报警信息-werror 把所有的告警信息转化为错误信息,并在告警发生时终止编译过程与体系结构相关的GCC选项-mcpu=type 针对不同的CPU 使用相应的CPU 指令。
可选择的type 有i386、i486、pentium 及i686 等-mieee-fp 使用IEEE 标准进行浮点数的比较-mno-ieee-fp 不使用IEEE 标准进行浮点数的比较-msoft-float 输出包含浮点库调用的目标代码-mshort 把int 类型作为16 位处理,相当于short int-mrtd 强行将函数参数个数固定的函数用ret NUM 返回,节省调用函数的一条指令使用GCC注意事项:1)GCC指令的一般格式为:Gcc [选项] 需编译的文件[选项] [目标文件] ,其中,目标文件可缺省,GCC默认生成可执行的文件名为a.out。
执行时时使用指令./a.out;2)在include 语句中,“<>”表示在标准路径中搜索头文件,““””表示在当前目录中搜索。
故代码中使用“#include<myhead.h>”,就需要添加GCC编译选项“-I”指定myhead.h 所在路径;3)选项“-L dir ”的功能与“-I dir”类似,在编译时指定所需库文件路径,-l指定相应的库名称。
Linux下的库文件命名时规定:必须以lib字母组合开头,后接库名称。
因此用-l 选项指定链接库名为libsunq.so ,在命令中选项写为-lsunq;GDB调试相关命令汇总如表1.2所示表1.2 GDB相关命令汇总功能命令描述单步执行与函数跟踪backtrace(或bt)查看各级函数调用及参数finish 执行到当前函数返回,然后停下来等待命令frame(或f)帧编号选择栈帧info(或i)locals 查看当前栈帧局部变量的值list(或l)列出源代码,接着上次的位置往下列,每次列10行list 行号列出从第几行开始的源代码list 函数名列出某个函数的源代码next(或n)执行下一行语句print(或p)打印表达式的值,通过表达式可以修改变量的值或者调用函数set var 修改变量的值start 开始执行程序,停在main函数第一行语句前面等待命令step(或s)执行下一行语句,如果有函数调用则进入到函数中断点break(或b)行号在某一行设置断点break 函数名在某个函数开头设置断点break...if... 设置条件断点continue(或c)从当前位置开始连续而非单步执行程序delete breakpoints 删除断点display 变量名跟踪查看一个变量,每次停下来都显示它的值disable breakpoints 禁用断点enable breakpoints 启用断点info(或i)breakpoints 查看当前设置了哪些断点run(或r)从头开始连续而非单步执行程序undisplay 取消对先前设置的那些变量的跟踪观察点watch 设置观察点info(或i)watchpoints 查看当前设置了哪些观察点x 从某个位置开始打印存储器的一段内容,全部当成字节来看,而不区分哪些字节属于哪些变量GDB使用注意事项:1)在Gcc 编译选项中一定要加入“-g”;2)只有在代码处于“运行”或“暂停”状态时才能查看变量值;3)设置断点后程序在指定行之前停止;2.实验目的1)掌握Linux C开发过程中的基本概念;2)掌握如GCC,GDB等开发工具的使用;3.实验内容将参考代码录入到greet.c文件中,编译执行后发现结果与预期不一致,请使用GDB调试,完成字符串反序输出功能;4.参考代码5.实验扩展思考1)如何使用GCC将一组功能相关的源文件编译成相应库文件(静态库或动态库自行选择),并使用代码形式演示如何使用编译好的库?2)分析以下代码,完成指定范围内数值累加功能:#include <stdio.h>int add_range(int low, int high){int i, sum;for (i = low; i <= high; i++)sum = sum + i;return sum;}int main(void){int result[100];result[0] = add_range(1, 10);result[1] = add_range(1, 100);printf("result[0]=%d\nresult[1]=%d\n", result[0], result[1]);return 0;}实验二:文件I/O操作1.实验相关知识简述“文件”是Unix/Linux平台的核心概念之一。
广义理解,可将普通文件、目录、设备、管道……均视为文件(Everything is File);狭义理解,文件仅代表普通文件。
涉及具体上下文时,需要结合语义对其进行区分。
Unix/Linux相关文件系统在组织文件时,将文件的数据与属性分离。
目录文件中记录子目录及所属文件的文件名和相应i节点,由i节点记录相应的数据存储位置及文件属性。
针对文件内容时行操作时,一般需要经历步骤为:打开/创建文件→操作文件→关闭文件。
打开/创建文件推荐使用系统调用open,若仅需新建文件,亦使用creat系统调用,但creat 不负责打开文件。
为保证程序运行时无异常发生,程序员必须对open返回值进行判断,若返回值为-1意味着文件打开失败,其原因或为进程已打开的文件数目超出可打开文件的最大值,或为相应路径下无对应文件(注意:Unix/Linux文件名区分大小写);当open调用成功时,将返回一个由内核管理生成的非负整型数值,对应术语为文件描述符(File Descriptor)。
对文件内容操作时,文件描述符将自动维护文件读写指针。
换句话说,多个进程可同时打开一个文件,并在各自的文件读写指针位置进行相应操作,程序员有责任对其进行合理规划,以保证数据有效性。
进程创建时,Linux内核将值为0,1,2这三个文件描述符预分配给标准输入设备、输出设备和错误输出设备。
若使用dup系统调用,可干预内核分配文件描述符,从而达到文件重定向的目的。
open语法要点如表2.1所示:表2.1 open语法要点头文件#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>功能打开或创建文件函数原型int open(const char* path, int flags)int open(const char* path, int flags, int perms)参数说明path 需打开或创建的文件路径名flags 文件打开方式:O_RDONLY:只读方式O_WRONLY:只写方式O_RDWR:读写方式O_CREAT:如果文件不存在就创建文件,并以参数perms设置文件权限O_EXCL:测试文件是否存在,如果O_CREAT创建文件时,文件已存在则返回错误消息O_TRUNC:如果文件存在,打开文件后将已存在的文件内容删除,并定位于文件开始处O_APPEND:打开文件,在尾部添加内容perms 新建文件时以八进制方式设置文件权限属性,只用于读或写时此参数可省略函数返回值成功:返回打开或新建文件的文件描述符失败:-1文件内容读写时,内核负责内存与文件所在存储设备之间的数据流动。
程序员负责规划代表文件读或写时使用的缓冲区大小与类型,其类型设置,通常与操作的目标文件类型相关。
l 当操作以二进制为单位存储的文件时,内存缓冲多使用byte类型数组;l 在操作以字符为单位的存储文件时,内在缓冲多使用char类型数组;注意:若违反文件编码方案,文件内容显示乱码;表2.2 read语法要点头文件#include <unistd.h>函数原型ssize_t read(int fd, void* buffer, size_t len)功能读取文件内容函数参数fd 所读文件的文件描述符buffer 存放文件读取内容的缓冲len 缓冲长度函数返回值成功:返回实际读取的字节数(不大于len),0表示到达文件结束位置; 失败:-1表2.3 write 语法要点头文件#include <unistd.h>函数原型ssize_t write(int fd, void* buffer, size_t len) 功能写文件内容函数参数fd 所写文件的文件描述符buffer 需写入文件的内容缓冲len 缓冲长度函数返回值成功:返回实际实际写入文件的字节数(=len); 失败:-1文件定位系统调用lseek实现文件读写指针在文件中移动。