Linux下C编程基础.ppt
第7章 Linux下C编程基础,Linux编程概述Linux下编辑器的使用viLinux c编译器gccLinux下的调试器gdb,Linux文化,Windows能够做到的,Linux也能够做到,Linux不能做到的就是人类不需要的,Linux编程概述Linux下编辑器的使用Linux c编译器gccLinux下的调试器gdb,例:Windows下的一个简单c程序,include main()char c;c=getchar();putchar(c);,Question,你的windows下的c程序,移植到linux下能否运行?涉及到的知识点:程序的形成过程 系统调用,可执行程序的形成过程,程序的源代码源代码不能直接运行,所以需要通过编译器(一种软件)来把源代码编译成直接用二进制代码指令表达的机器语言后,程序才能运行;机器语言是与硬件平台(主要是cpu)有关的,所以编译生成应用程序就必须要区分编译生成的是在什么硬件平台下运行的应用程序。,例如,51、ARM、MSP430、SPCA61等单片机,因为它们的CPU构架不同,所以所使用的机器语言也就不同。所以在使用C语言设计程序时,对于不同的单片机,其C源码可能都相同,但通过不同的编译器,生成的机器代码会是天壤之别。,准确的说法:必须满足一定条件,才可以移植。与系统调用有关。可以移植必须满足的条件:源代码中不涉及到与操作系统有关的系统调用。,系统调用函数与操作系统相关,是操作系统的一部分,不同的操作系统所使用的系统调用不一样。一般来说,如果两个操作系统差异很大,系统调用函数的可移植性就不高。例如 Windows 采用了系统调用的应用程序不能直接在 Linux 下编译运行。系统调用函数很多情况下需要访问系统特殊资源,使用系统调用时,该程序的状态将从用户态切换到内核态。,不同的c标准,ANSI C标准ISO C标准POSIX C标准SVID标准XPG标准,Linux得以流行的原因之一【遵循POSIX标准】,POSIX 表示可移植操作系统接口(Portable Operating System Interface),该标准由IEEE制定,并由国际标准化组织(ISO)接受为国际标准。,POSIX C标准,POSIX 标准最初是由 IEEE 开发的标准族,部分已经被 ISO 接受为国际标准。POSIX.1和POSIX.2 分别定义了兼容操作系统的 C 语言系统接口以及工具标准。这两个标准是通常提到的标准。表 1 所示为 26 项 POSIX 标准定义的头文件,表 2 所示为 26 项 POSIX 标准定义的 XSI 扩展头文件,表 3 所示为 8 项 POSIX 标准定义的可选头文件。,Linux对ansi c和posix c都是支持的,并且两种标准中都提供了相应的库函数和系统调用。但是windows只支持ansi c标准。linux下的系统调用一般选择符合posix标准的系统调用,这种系统调用在unix族操作系统中都可以使用。,Linux c编程的要领,一些简单的程序调用c提供的函数库就足够了,但是要做出功能强大的应用程序,就必须借助操作系统提供的系统调用,所以,linux下的c开发主要是要求你要掌握linux系统,包括它的运行机制,可用api,一些操作模式等等。c强大的功能和它的可移植性让它能在各种硬件平台上游刃自如。,CYGWIN,Cygwin是许多自由软件的集合,最初由Cygnus Solutions开发,用于各种版本的Microsoft Windows上,运行类UNIX系统。Cygwin的主要目的是通过重新编译,将POSIX系统(例如Linux,BSD,以及其他Unix系统)上的软件移植到Windows上。Cygwin包括了一套库,该库在Win32系统下实现了POSIX系统调用的API;还有一套GNU开发工具集(比如GCC、GDB)。,MinGW,MinGW(Minimalist GNU for Windows),又称mingw32,是将GCC编译器和GNU Binutils移植到Win32平台下的产物,包括一系列头文件(Win32API)、库和可执行文件。MinGW是从Cygwin(版)基础上发展而来。,MSYS,is a Bourne Shell command line interpreter system.Offered as an alternative to Microsofts cmd.exe,this provides a general purpose command line environment,which is particularly suited to use with MinGW,for porting of many Open Source applications to the MS-Windows platform;a light-weight fork of Cygwin-1.3,it includes a small selection of Unix tools,chosen to facilitate that objective.MSYS is a collection of GNU utilities such as bash,make,gawk and grep to allow building of applications and programs which depend on traditionally UNIX tools to be present.It is intended to supplement MinGW and the deficiencies of the cmd shell.,Linux编程概述Linux下编辑器的使用 Linux c编译器gccLinux下的调试器gdb,Linux下的 C 语言程序设计与在其他环境中的 C 程序设计一样,主要涉及到编辑器、编译链接器、调试器及项目管理工具。(1)编辑器Linux 下的编辑器就如 Windows 下的 word、记事本等一样,完成对所录入文字的编辑功能。Linux 中最常用的编辑器有 Vi(Vim)和 Emacs,着重介绍 Vi。,(2)编译链接器编译是指源代码转化生成可执行代码的过程,它所完成工作主要如图所示。在 Linux 中,最常用的编译器是 Gcc 编译器。它是 GNU推出的功能强大、性能优越的多平台编译器,其执行效率与一般的编译器相比平均效率要高20%30%,堪称为 GNU 的代表作品之一。,(3)调试器在编程的过程当中,往往调试所消耗的时间远远大于编写代码的时间。因此,有一个功能强大、使用方便的调试器是必不可少的。Gdb 是绝大多数 Linux 开发人员所使用的调试器,它可以方便地设置断点、单步跟踪等,足以满足开发人员的需要。,(4)项目管理器Linux 中的项目管理器“make”有些类似于 Windows 中 Visual C+里的“工程”,它是一种控制编译或者重复编译软件的工具。,进入 ViLinux 系统提供了一个完整的编辑器家族系列,如 Ed、Ex、Vi 和 Emacs 等。按功能它们可以分为两大类:行编辑器(Ed、Ex)和全屏幕编辑器(Vi、Emacs)。行编辑器每次只能对一行进行操作,使用起来很不方便。而全屏幕编辑器可以对整个屏幕进行编辑,用户编辑的文件直接显示在屏幕上,从而克服了行编辑的那种不直观的操作方式,便于用户学习和使用,具有强大的功能。,Vi 是 Linux 系统的第一个全屏幕交互式编辑程序,它从诞生至今一直得到广大用户的青睐,历经数十年仍然是人们主要使用的文本编辑工具。,Vi 的模式(1)命令行模式用户在用 Vi 编辑文件时,最初进入的为一般模式。在该模式中可以通过上下移动光标进行“删除字符”或“整行删除”等操作,也可以进行“复制”、“粘贴”等操作,但无法编辑文字。(2)插入模式只有在该模式下,用户才能进行文字编辑输入,用户按ESC键回到命令行模式。(3)底行模式在该模式下,光标位于屏幕的底行。用户可以进行文件保存或退出操作,也可以设置编辑环境,如寻找字符串、列出行号等。,Vi 的基本流程(1)进入 Vi,即在命令行下键入 Vi hello(文件名)。此时进入的是命令行模式,光标位于屏幕的上方,如图所示。,(2)在命令行模式下键入 i 进入到插入模式,如图所示。可以看出,在屏幕底部显示有“插入”表示插入模式,在该模式下可以输入文字信息。,(3)最后,在插入模式中,输入“Esc”,则当前模式转入命令行模式,并在底行行中输入“:wq”(存盘退出)进入底行模式,如图所示。这样,就完成了一个简单的 Vi 操作流程:命令行模式插入模式底行模式。由于 Vi在不同的模式下有不同的操作功能,因此要时刻注意屏幕最下方的提示,分清所在的模式。,Vi 的各模式功能键(1)命令行模式常见功能键如表所示。,(2)插入模式的功能键只有一个,也就是 Esc 退出到命令行模式。(3)底行模式常见功能键如表所示。,初探 EmacsEmacs 不仅仅是一款功能强大的编译器,而且是一款融合编辑、编译、调试于一体的开发环境。,emacs文本编辑器可以用来编辑文本、剪辑和粘贴文本内容、提供个人日历和日记,阅读Usenet新闻、发送电子邮件,同时还是一种程序语言解释器,可以编辑C、Lisp、Tev源代码文件、以及Linux的Shell。emacs是由 Richard Stallman发明的,这位发明者还创建了自由软件基金会(简称FSF)。最初的emacs是用来编辑宏命令的,现已进一步扩充为 UNIX用户中装机用户数量最大、功能最齐全的免费文本编辑器了。,Emacs 的使用和 Vi 截然不同。Emacs只有一种模式,也就是编辑模式,而且它的命令全靠功能键完成。因此,功能键也就相当重要了。但 Emacs 却还使用一个不同 Vi 的“模式”,它的“模式”是指各种辅助环境。比如,当编辑普通文本时,使用的是“文本模式”(Text Mode),而当他们写程序时,使用的则是如“c”模式”“Shell 模式”等。,Emacs 的工作窗口分为上下两个部分,上部为编辑窗口,底部为命令显示窗口,用户执行功能键的功能都会在底部有相应的显示,有时也需要用户在底部窗口输入相应的命令。,Linux编程概述Linux下编辑器的使用 Linux c编译器gccLinux下的调试器gdb,Gcc 编译器GNU CC(简称为 Gcc)是 GNU 项目中符合 ANSI C 标准的编译系统,能够编译用 C、C+和 Object C 等语言编写的程序。Gcc 不仅功能强大,而且可以编译如 C、C+、Object C、Java、Fortran、Pascal、Modula-3 和 Ada 等多种语言。Gcc 是一个交叉平台编译器,它能够在当前 CPU 平台上为多种不同体系结构的硬件平台开发软件,因此尤其适合在嵌入式领域的开发编译。下表是 Gcc 支持编译源文件的后缀及其解释。,Gcc 编译流程解析Gcc 的编译流程分为了 4 个步骤,分别为:预处理(Pre-Processing);编译(Compiling);汇编(Assembling);链接(Linking)。首先,有以下 hello.c 源代码:,(1)预处理阶段在该阶段,编译器将上述代码中的 stdio.h 编译进来,并且用户可以使用 Gcc 的选项“-E”进行查看,该选项的作用是让 Gcc 在预处理结束后停止编译过程。Gcc 指令的一般格式为:Gcc 选项 要编译的文件 选项 目标文件其中,目标文件可缺省,Gcc 默认生成可执行的文件,命为:编译文件.out,在此处,选项“-o”是指目标文件,由表可知,“.i”文件为已经过预处理的 C 原始程序。以下列出了 hello.i 文件的部分内容:,由此可见,Gcc 确实进行了预处理,它把“stdio.h”的内容插入到 hello.i 文件中。(2)编译阶段接下来进行的是编译阶段,在这个阶段中,Gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,Gcc 把代码翻译成汇编语言。用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。,以下列出了 hello.s 的内容,可见 Gcc 已经将其转化为汇编了。,(3)汇编阶段汇编阶段是把编译阶段生成的“.s”文件转成目标文件,读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了。如下所示:(4)链接阶段在成功编译之后,就进入了链接阶段。在这里涉及到一个重要的概念:函数库。,可以重新查看这个小程序,在这个程序中并没有定义“printf”的函数实现,且在预编译中包含进的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,Gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。,函数库一般分为静态库和动态库两种。静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。Gcc 在编译时默认使用动态库。完成了链接之后,Gcc 就可以生成可执行文件,如下所示。,运行该可执行文件,出现正确的结果如下。,Gcc 编译选项分析 Gcc 有超过 100 个的可用选项,主要包括总体选项、告警和出错选项、优化选项和体系结构相关选项。以下对每一类中最常用的选项进行讲解。,(1)总体选项Gcc 的总结选项如表所示。,“-I dir”正如上表中所述,“-I dir”选项可以在头文件的搜索路径列表中添加 dir 目录。由于 Linux中头文件都默认放到了“/usr/include/”目录下,因此,当用户希望添加放置在其他位置的头文件时,就可以通过“-I dir”选项来指定,这样,Gcc 就会到相应的位置查找对应的目录。比如在“/root/workplace/Gcc”下有两个文件:,这样,就可在 Gcc 命令行中加入“-I”选项:,这样,Gcc 就能够执行出正确结果。,“-L dir”选项“-L dir”的功能与“-I dir”类似,能够在库文件的搜索路径列表中添加dir目录。需要注意的是,“-I dir”和“-L dir”都只是指定了路径,而没有指定文件,因此不能在路径中包含文件名。,(2)告警和出错选项Gcc 的告警和出错选项如表所示。,下面结合实例对这几个告警和出错选项进行简单的讲解。如有以下程序段:,考虑一下有哪些问题?“-ansi”该选项强制 Gcc 生成标准语法所要求的告警信息,尽管这还并不能保证所有没有警告的程序都是符合 ANSI C 标准的。运行结果如下所示:,可以看出,该选项并没有发现“long long”这个无效数据类型的错误。“-pedantic”允许发出 ANSI C 标准所列的全部警告信息,同样也保证所有没有警告的程序都是符合ANSI C 标准的。其运行结果如下所示:,可以看出,使用该选项查看出了“long long”这个无效数据类型的错误。“-Wall”允许发出 Gcc 能够提供的所有有用的报警信息。该选项的运行结果如下所示:,使用“-Wall”选项找出了未使用的变量 tmp,但它并没有找出无效数据类型的错误。另外,Gcc 还可以利用选项对单独的常见错误分别指定警告,有关具体选项的含义可以查看 Gcc 手册进行学习。,(3)优化选项Gcc 可以对代码进行优化,不同的优化级别对应不同的优化处理工作。(4)体系结构相关选项这些体系结构相关选项在嵌入式的设计中会有较多的应用,根据不同体系结构将对应的选项进行组合处理。,Linux编程概述Linux下编辑器的使用Linux c编译器gccLinux下的调试器gdb,Gdb 调试器如何提高程序员的调试效率,更好更快地定位程序中的问题从而加快程序开发的进度,如Windows下的一些调试工具,VC自带的如设置断点、如单步跟踪等,那么,Linux在下有什么很好的调试工具呢?Gdb调试器是一款GNU开发组织并发布的 UNIX/Linux下的程序调试工具。虽然,它没有图形化的友好界面,但是它强大的功能也足以与微软的VC工具等媲美。,Gdb 使用流程首先,打开Linux下的编辑器Vi,编辑如下代码。,在保存退出后首先使用 Gcc 对 test.c 进行编译,注意一定要加上选项“-g”,这样编译出的可执行代码中才包含调试信息,否则之后 Gdb 无法载入该可执行文件。,虽然这段程序没有错误,但调试完全正确的程序可以更加了解 Gdb 的使用流程。接下来就启动 Gdb 进行调试。注意,Gdb 进行调试的是可执行文件,而不是如“.c”的源代码,因此,需要先通过 Gcc 编译生成可执行文件才能用 Gdb 进行调试。,可以看出,在 Gdb 的启动画面中指出了 Gdb 的版本号、使用的库文件等信息,接下来就进入了由“(gdb)”开头的命令行界面了。,(1)查看文件在 Gdb 中键入“l”(list)就可以查看所载入的文件,如下所示:在 Gdb 的命令中都可使用缩略形式的命令,如“l”代便“list”,“b”代表“breakpoint”,“p”代表“print”等,也可使用“help”命令查看帮助信息。,可以看出,Gdb 列出的源代码中明确地给出了对应的行号,这样就可以大大地方便代码的定位。(2)设置断点设置断点是调试程序中是一个非常重要的手段,它可以使程序到一定位置暂停它的运行。因此,程序员在该位置处可以方便地查看变量的值、堆栈情况等,从而找出代码的症结所在。在 Gdb 中设置断点非常简单,只需在“b”后加入对应的行号即可。如下所示:,要注意的是,在 Gdb 中利用行号设置断点是指代码运行到对应行之前将其停止。(3)查看断点情况在设置完断点之后,用户可以键入“info b”来查看设置断点情况,在 Gdb 中可以设置多个断点。,(4)运行代码接下来就可运行代码了,Gdb 默认从首行开始运行代码,可键入“r”(run)即可(若想从程序中指定行开始运行,可在 r 后面加上行号)。,可以看到,程序运行到断点处就停止了。,(5)查看变量值在程序停止运行之后,程序员所要做的工作是查看断点处的相关变量值。在 Gdb 中只需键入“p”变量值即可,如下所示:,Gdb 在显示变量值时都会在对应值之前加上“$N”标记,它是当前变量值的引用标记,所以以后若想再次引用此变量就可以直接写作“$N”,而无需写冗长的变量名。(6)单步运行单步运行可以使用命令“n”(next)或“s”(step),它们之间的区别在于:若有函数调用的时候,“s”会进入该函数而“n”不会进入该函数。因此,“s”就类似于 VC 等工具中的“step in”,“n”类似与 VC 等工具中的“step over”。它们的使用如下所示:,可见,使用“n”后,程序显示函数 sum 的运行结果并向下执行,而使用“s”后则进入到 sum 函数之中单步运行。(7)恢复程序运行在查看完所需变量及堆栈情况后,就可以使用命令“c”(continue)恢复程序的正常运行了。这时,它会把剩余还未执行的程序执行完,并显示剩余程序中的执行结果。以下是之前使用“n”命令恢复后的执行结果:,可以看出,程序在运行完后退出,之后程序处于“停止状态”。Gdb 基本命令Gdb 的命令可以通过查看 help 进行查找,由于 Gdb 的命令很多,因此 Gdb 的 help 将其分成了很多种类(class),可以通过进一步查看相关 class 找到相应命令。如下所示:,上述列出了 Gdb 各个分类的命令,注意底部的加粗部分说明其为分类命令。接下来可以具体查找各分类种的命令。如下所示:,至此,若用户想要查找 call 命令,就可键入“help call”。,若已知命令名,直接键入“help command”也可以。Gdb 中的命令主要分为以下几类:工作环境相关命令、设置断点与恢复命令、源代码查看命令、查看运行数据相关命令及修改运行参数命令。,由于设置断点在 Gdb 的调试中非常重要,所以在此再着重讲解一下 Gdb 中设置断点的方法。Gdb 中设置断点有多种方式:其一是按行设置断点,设置方法在前面已经指出。另外还可以设置函数断点和条件断点,在此结合上一小节的代码,具体介绍后两种设置断点的方法。函数断点Gdb 中按函数设置断点只需把函数名列在命令“b”之后,如下所示:,要注意的是,此时的断点实际是在函数的定义处,也就是在 16 行处(注意第 16 行还未执行)。条件断点Gdb 中设置条件断点的格式为:b 行数或函数名 if 表达式。具体实例如下所示:,可以看到,该例中在第 8 行(也就是运行完第 7 行的 for 循环)设置了一个“i=0”的条件断点,在程序运行之后可以看出,程序确实在 i 为 10 时暂停运行。,Gdb 还可以修改运行时的参数,并使该变量按照用户当前输入的值继续运行。它的设置方法为:在单步执行的过程中,键入命令“set 变量设定值”。这样,在此之后,程序就会按照该设定的值运行了。下面,结合上一节的代码将 n 的初始值设为 4,其代码如下所示:,可以看到,最后的运行结果确实比之前的值大了4。,补:make,make是一个工具程序,经由读取叫做“makefile”的文件,自动化建构软件。它是一种转化文件形式的工具,转换的目标称为“target”;与此同时,它也检查文件的依赖关系,如果需要的话,它会调用一些外部软件来完成任务。大多数情况下,它被用来编译源代码,生成结果代码,然后把结果代码连接起来生成可执行文件或者库文件。它使用叫做“makefile”的文件来确定一个target文件的依赖关系,然后把生成这个target的相关命令传给shell去执行。许多现代软件的开发中,集成开发环境已经取代make,但是在Unix环境中,仍然有许多任务程师采用make来协助软件开发。,