《UNIX下C语言开发环境》由会员分享,可在线阅读,更多相关《UNIX下C语言开发环境(32页珍藏版)》请在金锄头文库上搜索。
1、Unix Programming第四章UNIX下的C语言开发环境Unix Programming6.1 程序设计环境 学习程序设计从程序语言开始,但还应了解程序执行和程序与外界的交互问题。1.理想态的程序运行环境用户程序直接控制和使用各种设备,完成各种操作。Unix Programming针对一个简单程序:main() int c; while ( ( c=getchar() != EOF )putchar(c);认为执行过程为:在单用户单任务环境中基本符合。Unix Programming2. 多任务环境下程序执行多任务中每一时刻都会有多个用户程序提出访问请求,因此会有:如此混乱的情况,程序
2、将无法运行。Unix Programming为使多道环境中的程序正确执行,需要OS管理。用户程序需要系统核心区程序的管理,达到各自任务的执行。Unix Programming6.2 基于系统支持的程序设计1. 建立系统编程的思想 理解多道环境程序执行状况,转换用户程序是执行主体的认识。 了解OS可提供的服务及服务方式。 充分利用OS提供服务功能解决实际问题。 尽量使编写的程序最大限度的满足系统平台的支持能力。Unix operating systemUnix operating system1.gcc与gdb1.1UNIX和C语言C是一种在UNIX操作系统的早期就被广泛使用的通用编程语言,它最
3、早是由贝尔实验室的DennisRitchie为了UNIX的辅助开发而写的。C是所有版本的UNIX上的系统语言。几乎任何一种计算机上都有至少一种能用的C编译器;并且它的语法和函数库在不同的平台上都是统一的。80年代末期美国国家标准协会(AmericanNationalStandardsInstitute)发布了一个被称为ANSIC的C语言标准,这保证了在不同平台上的C的一致性。Unix operating systemUnix operating system1.gcc与gdb1.2GNUC编译器GNUC编译器(gcc)是一个全功能的ANSIC兼容编译器,它是所有UNIX系统可用的C编译器。gc
4、c是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%30%。Unix operating systemUnix operating system3.1LINUX下C语言编程概述Unix operating systemUnix operating system1.gcc与gdbgcc编译过程:预处理,对源代码文件中的文件包含(include)、预编译语句(如宏定义define等)进行分析。编译,就是把C/C+代码“翻译”成汇编代码。汇编,将第二步输出的汇编代码翻译成符合一定格式的机器代码,生成以.o为后缀的目标文件。链接,将上步生成的目标文件和系
5、统库的目标文件和库文件链接起来,最终生成了可以在特定平台运行的可执行文件。Unix operating systemUnix operating system1. Gcc编译流程解析如本章开头提到的,Gcc的编译流程分为了4个步骤,分别为: 预处理(Pre-Processing); 编译(Compiling); 汇编(Assembling); 链接(Linking)。下面就具体来查看一下Gcc是如何完成4 个步骤的。首先,有以下hello.c源代码:#includeint main()printf(Hello! This is our embedded world!n);return 0;3.
6、3Gcc编译器Unix operating systemUnix operating system(1)预处理阶段在该阶段,编译器将上述代码中的stdio.h编译进来,并且用户可以使用Gcc的选项“-E”进行查看,该选项的作用是让Gcc在预处理结束后停止编译过程。rootlocalhost Gcc# Gcc E hello.c o hello.i在此处,选项“-o”是指目标文件,由上表可知,“.i”文件为已经过预处理的C 原始程序。以下列出了hello.i文件的部分内容:typedef int (*_gconv_trans_fct) (struct _gconv_step *,struct _
7、gconv_step_data *, void *,_const unsigned char *,_const unsigned char *,_const unsigned char *, unsigned char *,size_t *);Unix operating systemUnix operating system#2hello.c2intmain()printf(Hello!Thisisourembeddedworld!n);return0;由此可见,Gcc确实进行了预处理,它把“stdio.h”的内容插入到hello.i文件中。Unix operating systemUnix
8、 operating system(2)编译阶段接下来进行的是编译阶段,在这个阶段中,Gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,Gcc 把代码翻译成汇编语言。用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。rootlocalhost Gcc# Gcc S hello.i o hello.s以下列出了hello.s的内容,可见Gcc已经将其转化为汇编了,感兴趣的读者可以分析一下这一行简单的C语言小程序是如何用汇编代码实现的。.file hello.c“.section .rodata.align 4.LC0:.st
9、ring Hello! This is our embedded world!.text.globl main.type main, functionmain:pushl %ebpmovl %esp, %ebpsubl $8, %espandl $-16, %espmovl $0, %eaxaddl $15, %eax.section .note.GNU-stack,progbitsUnix operating systemUnix operating system(3)汇编阶段汇编阶段是把编译阶段生成的“.s”文件转成目标文件,读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进
10、制目标代码了。如下所示:rootlocalhost Gcc# Gcc c hello.s o hello.oGcc编译器Unix operating systemUnix operating system(4)链接阶段在成功编译之后,就进入了链接阶段。在这里涉及到一个重要的概念:函数库。读者可以重新查看这个小程序,在这个程序中并没有定义“printf”的函数实现,且在预编译中包含进的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?最后的答案是:系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,Gcc 会到
11、系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。函数库一般分为静态库和动态库两种。静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的libc.so.6就是动态库。Gcc在编译时默认使用动态库。完成了链接之后,Gcc就可以生成可执行文件,
12、如下所示。rootlocalhost Gcc# Gcc hello.o o hello运行该可执行文件,出现正确的结果如下。rootlocalhost Gcc# ./helloHello! This is our embedded world!Unix operating systemUnix operating systemGcc编译选项:Gcc编译器Unix operating systemUnix operating system1.UNIX下的C语言开发环境gcc遵循的文件类型规定.c为后缀的文件,C语言源代码文件;.a为后缀的文件,是由目标文件构成的档案库文件;.C,.cc或.cxx
13、为后缀的文件,是C+源代码文件;.h为后缀的文件,是程序所包含的头文件;.i为后缀的文件,是已经预处理过的C源代码文件;.ii为后缀的文件,是已经预处理过的C+源代码文件;.m为后缀的文件,是Objective-C源代码文件;.o为后缀的文件,是编译后的目标文件;.s为后缀的文件,是汇编语言源代码文件;.S为后缀的文件,是经过预编译的汇编语言源代码文件。Unix operating systemUnix operating system头文件头文件是用来提供常量的定义和系统和函数调用的声明,这些头文件通常放在/usr/include和其子目录中。根据不同的Linux版本,头文件可能放在/usr
14、/include/sys和/usr/include/linux.#includeUnix operating systemUnix operating system库函数库函数是一些预先编译好的函数的集合,这些函数可以有很好的重用性。通常来讲,它们包含有相关的函数集合来完成一项常用任务。典型的库函数有屏幕处理函数(curses和ncurses库)和数据库访问函数(dbm库)。标准系统函数通常存放在/lib和/usr/lib中。C编译器需要被告知搜索哪个库,否则缺省情况下只搜索标准库。传统静态库.aExamplesare/usr/lib/libc.aand/usr/X11/lib/libX11.
15、aforthestandardClibraryandtheX11library共享库.soOnatypicalLinuxsystem,thesharedversionofthestandardmathlibraryis/usr/lib/libm.soUnix operating systemUnix operating system1.gcc与gdb1.5gdb调试和分析选项gdb基本命令file装入想要调试的可执行文件;kill终止正在调试的程序;list列出产生执行文件的源代码的一部分;next执行一行源代码但不进入函数内部;step执行一行源代码而且进入函数内部;run执行当前被调试的程
16、序;quit终止gdb;watch使你能监视一个变量的值而不管它何时被改变;break在代码里设置断点,这将使程序执行到这里时被挂起;make使你能不退出gdb就可以重新产生可执行文件;shell使你能不离开gdb就执行UNIXshell命令.Unix operating systemUnix operating system1.gcc与gdbgdb调试举例/*gdbtest.c*/#includeintsum(intm);intmain(intargc,char*argv)inti,n=0;sum(50);for(i=1;i=50;i+)n+=i;printf(“Thesumof1-50is
17、%dn”,n);intsum(intm)inti,n=0;for(i=1;i=m;i+)n+=i;printf(“Thesumof1-%dis%dn”,m,n);例:$gcc-Wall-ggdbtest.c-ogdbtestUnix operating systemUnix operating system1.gcc与gdb1.启动gdb开始调试例1:$gdbgdbtest例2:$gdb(gdb)Unix operating systemUnix operating system1.gcc与gdb2.在gdb中查看源代码例:(gdb)listlist也可以缩写为lUnix operating
18、systemUnix operating system1.gcc与gdb3.在gdb中设置断点例1:(gdb)break9break也可以缩写为b注意:在gdb中利用行号设置断点,是指代码运行到对应行号之前暂停;gdb中可以设置多个断点。Unix operating systemUnix operating system1.gcc与gdb3.在gdb中设置断点例2:(gdb)breaksum设置函数断点,在函数体开始处例3:(gdb)break10ifi=10设置条件断点Unix operating systemUnix operating system1.gcc与gdb4.开看断点情况例:(
19、gdb)infobreakUnix operating systemUnix operating system1.gcc与gdb5.运行代码例:(gdb)runrun也可以缩写为rUnix operating systemUnix operating system1.gcc与gdb6.查看变量例:(gdb)printiprint也可以缩写为p;i为变量名“$N”是当前变量值的引用标记Unix operating systemUnix operating system1.gcc与gdb7.单步运行单步运行可以使用命令“step”和“next”,它们之间的区别在于:若有函数调用的时候“step”会
20、进入函数体,而“next”不会进入该函数;8.恢复程序运行使用命令“continue”可以恢复程序正常运行,直到遇到下一个断点或者到程序结束;gdb中程序有“运行”、“暂停”和“停止”三种状态。“暂停”状态时,函数的地址、参数、局部变量都被压入“栈”中,故可以查看函数的各种属性;函数处于“停止”状态时,“栈”会自动撤销,也就无法查看函数的信息了。Unix operating systemUnix operating system2.make工程管理器2.1为什么要使用make?工作量问题:对于拥有多个(上百个)源文件的软件项目,只需编写一次编译过程,而不需要在每次源文件修改后重复输入众多的文件
21、名和编译命令进行编译;效率问题:make能够根据文件的时间戳自动发现更新过的源文件,并通过读入Makefile文件来对更新的源文件进行编译而对其它文件只进行链接操作。Unix operating systemUnix operating system2.make命令2.2Makefile的格式Makefile是make读入的唯一配置文件,Makefile文件通常包含如下内容:需要由make创建的目标体(target),通常是目标文件或可执行文件;要创建的目标体所依赖的文件(dependency_file);创建每个目标体时需要运行的命令(commmand)。Makefile格式:target:dependency_filecommandcommand之前必须有个“tab”