《《嵌入式Linux操作系统》3 嵌入式Linux编程环境.pdf》由会员分享,可在线阅读,更多相关《《嵌入式Linux操作系统》3 嵌入式Linux编程环境.pdf(34页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、 华清远见嵌入式学院:www.embedu.org 华清远见嵌入式学院:www.embedu.org 嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org 第 3 章 嵌入式 Linux 编程环境 本章内容 本章内容包括常用的 Linux 开发工具使用技巧和 Linux 编程技术。本章内容比 Linux 编程方面的书籍简略得多,重点介绍常用的 Linux 编程工具和技巧。通过本章学习可以使读者快速掌握基本的 Linux 开发工具,为后续的嵌入式 Linux 开发打下基础。嵌入式 Linux 操作系统第 3 章 嵌入式 Linux
2、 编程环境 华清远见嵌入式学院:www.embedu.org 3.1 Linux 编辑器 vi 的使用 Linux 系统提供了一个完整的编辑器家族系列,如 ed、ex、vi 和 emacs 等。按功能它们可以分为两大类:行编辑器(ed、ex)和全屏幕编辑器(vi、emacs)。行编辑器每次只能对单行进行操作,使用起来很不方便。而全屏幕编辑器可以对整个屏幕进行编辑,用户编辑的文件直接显示在屏幕上,从而克服了行编辑的那种不直观的操作方式,便于用户学习和使用,具有强大的功能。vi 是 Linux 系统的第一个全屏幕交互式编辑程序,它从诞生至今一直得到广大用户的青睐,历经数十年仍然是人们主要使用的文本
3、编辑工具,足以见其生命力之强,而强大的生命力是其强大的功能带来的。由于大多数读者在此之前都已经用惯了 Windows 的 word 等编辑器,因此,在刚刚接触时总会或多或少不适应,但只要习惯之后,就能感受到它的方便与快捷。3.1.1 vi 的模式的模式 vi 有 3 种模式,分别为命令行模式、插入模式及底行模式各模式的功能,下面具体进行介绍。(1)命令行模式 用户在用 vi 编辑文件时,最初进入的为一般模式。在该模式中可以通过上下移动光标进行“删除字符”或“整行删除”等操作,也可以进行“复制”、“粘贴”等操作,但无法编辑文字。(2)插入模式 只有在该模式下,用户才能进行文字编辑输入,用户课按E
4、SC键回到命令行模式。(3)底行模式 在该模式下,光标位于屏幕的底行。用户可以进行文件保存或退出操作,也可以设置编辑环境,如寻找字符串、列出行号等。3.1.2 vi 的基本流程的基本流程(1)进入 vi,即在命令行下键入 vi hello(文件名)。此时进入的是命令行模式,光标位于屏幕的上方,如图 3.1 所示。(2)在命令行模式下键入 i 进入到插入模式,如图 3.2 所示。可以看出,在屏幕底部显示有“插入”表示插入模式,在该模式下可以输入文字信息。嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org 图 3.1 进入 vi
5、命令行模式 图 3.2 进入 vi 插入模式 嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org(3)最后,在插入模式中,输入“Esc”,则当前模式转入命令行模式,并在底行行中输入“:wq”(存盘退出)进入底行模式,如图 3.3 所示。这样,就完成了一个简单的 vi 操作流程:命令行模式插入模式底行模式。由于 vi 在不同的模式下有不同的操作功能,因此,读者一定要时刻注意屏幕最下方的提示,分清所在的模式。图 3.3 进入 Vi 底行模式 3.1.3 vi 的各模式功能键的各模式功能键(1)命令行模式常见功能键如表 3.1 所示
6、。表 3.1 vi 命令行模式功能键 目 录 目 录 内 容 I 切换到插入模式,此时光标当于开始输入文件处 A 切换到插入模式,并从目前光标所在位置的下一个位置开始输入文字 O 切换到插入模式,且从行首开始插入新的一行 ctrl+b 屏幕往“后”翻动一页 ctrl+f 屏幕往“前”翻动一页 ctrl+u 屏幕往“后”翻动半页 ctrl+d 屏幕往“前”翻动半页 0(数字 0)光标移到本行的开头 G 光标移动到文章的最后 嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org nG 光标移动到第 n 行$移动到光标所在行的“行尾”
7、n 光标向下移动 n 行/name 在光标之后查找一个名为 name 的字符串?name 在光标之前查找一个名为 name 的字符串 X 删除光标所在位置的“后面”一个字符 续表 目 录 目 录 内 容 X 删除光标所在位置的“前面”一个字符 dd 删除光标所在行 ndd 从光标所在行开始向下删除 n 行 yy 复制光标所在行 nyy 复制光标所在行开始的向下 n 行 p 将缓冲区内的字符粘贴到光标所在位置(与 yy搭配)U 恢复前一个动作 (2)插入模式的功能键只有一个,也就是 Esc 退出到命令行模式。(3)底行模式常见功能键如表 3.2 所示。表 3.2 vi 底行模式功能键 目 录 目
8、 录 内 容:w 将编辑的文件保存到磁盘中:q 退出 Vi(系统对做过修改的文件会给出提示):q!强制退出 Vi(对修改过的文件不作保存):wq 存盘后退出:w filename 另存一个命为 filename 的文件:set nu 显示行号,设定之后,会在每一行的前面显示对应行号:set nonu 取消行号显示 3.2 gcc 编译器编译器 GNU CC(简称为 Gcc)是 GNU 项目中符合 ANSI C 标准的编译系统,能够编译用 C、C+和 Object C 等语言编写的程序。gcc 不仅功能强大,而且可以编译如 C、C+、Object C、Java、Fortran、Pascal、Mo
9、dula-3 和 Ada 等多种语言,而且 gcc 又是一个交叉平台编译器,它能够在当前 CPU 平台上为多种不同体系结构的硬件平台开嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org 发软件,因此尤其适合在嵌入式领域的开发编译。本章中的示例,除非特别注明,否则均采用 gcc 版本为 4.0.0。下表 3.3 是 gcc 支持编译源文件的后缀及其解释。表 3.3 Gcc 所支持后缀名解释 后 缀 名 所对应的语言 后 缀 名 所对应的语言.c C 原始程序.s/.S 汇编语言原始程序.C/.cc/.cxx C+原始程序.h 预
10、处理文件(头文件).m Objective-C 原始程序.o 目标文件.i 已经过预处理的 C 原始程序.a/.so 编译后的库文件.ii 已经过预处理的 C+原始程序 3.2.1 gcc 编译流程解析编译流程解析 如本章开头提到的,gcc 的编译流程分为了 4 个步骤,分别为:预处理(Pre-Processing);编译(Compiling);汇编(Assembling);链接(Linking)。下面就具体来查看一下 gcc 是如何完成 4 个步骤的。首先,有以下 hello.c 源代码:#include int main()printf(Hello!This is our embedded
11、 world!n);return 0;(1)预处理阶段 在该阶段,编译器将上述代码中的 stdio.h 编译进来,并且用户可以使用 gcc 的选项“-E”进行查看,该选项的作用是让 gcc 在预处理结束后停止编译过程。rootlocalhost Gcc#gcc E hello.c o hello.i 在此处,选项“-o”是指目标文件,由表 3.3 可知,“.i”文件为已经过预处理的C 原始程序。以下列出了 hello.i 文件的部分内容:typedef int(*_gconv_trans_fct)(struct _gconv_step*,struct _gconv_step_data*,voi
12、d*,_const unsigned char*,_const unsigned char*,嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org _const unsigned char*,unsigned char*,size_t*);#2 hello.c 2 int main()printf(Hello!This is our embedded world!n);return 0;由此可见,Gcc 确实进行了预处理,它把“stdio.h”的内容插入到 hello.i 文件中。(2)编译阶段 接下来进行的是编译阶段,在这个阶
13、段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。rootlocalhost Gcc#gcc S hello.i o hello.s 以下列出了 hello.s 的内容,可见 gcc 已经将其转化为汇编了,感兴趣的读者可以分析一下这一行简单的 C 语言小程序是如何用汇编代码实现的。.file hello.c .section.rodata .align 4.LC0:.string Hello!This is our embedded wo
14、rld!.text.globl main .type main,function main:pushl%ebp movl%esp,%ebp subl$8,%esp andl$-16,%esp movl$0,%eax addl$15,%eax addl$15,%eax shrl$4,%eax sall$4,%eax 嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org subl%eax,%esp subl$12,%esp pushl$.LC0 call puts addl$16,%esp movl$0,%eax leave ret
15、 .size main,.-main .ident GCC:(GNU)4.0.0 20050519(Red Hat 4.0.0-8).section.note.GNU-stack,progbits (3)汇编阶段 汇编阶段是把编译阶段生成的“.s”文件转成目标文件,读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了。如下所示:rootlocalhost Gcc#gcc c hello.s o hello.o (4)链接阶段 在成功编译之后,就进入了链接阶段。在这里涉及到一个重要的概念:函数库。读者可以重新查看这个小程序,在这个程序中并没有定义“printf”的函数实现
16、,且在预编译中包含进的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢?最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。函数库一般分为静态库和动态库两种。静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。动态库与之相反,在编译链接时并没有
17、把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。rootlocalhost Gcc#gcc hello.o o hello 运行该可执行文件,出现正确的结果如下。rootlocalhost Gcc#./hello Hello!This is our embedded world!3.2.2 gcc 编译选项分析编译选项分析 嵌入式 Linux 操作系统第 3 章 嵌入式 Linux
18、编程环境 华清远见嵌入式学院:www.embedu.org gcc 有超过 100 个的可用选项,主要包括总体选项、告警和出错选项、优化选项和体系结构相关选项。以下对每一类中最常用的选项进行讲解。(1)总体选项 gcc 的总结选项如表 3.4 所示,很多在前面的示例中已经有所涉及。表 3.4 gcc 总体选项列表 后 缀 名 所对应的语言-c 只是编译不链接,生成目标文件“.o”-S 只是编译不汇编,生成汇编代码-E 只进行预编译,不做其他处理-g 在可执行程序中包含标准调试信息-o file 把输出文件输出到 file 里-v 打印出编译器内部编译各过程的命令行信息和编译器的版本-I dir
19、 在头文件的搜索路径列表中添加 dir 目录-L dir 在库文件的搜索路径列表中添加 dir 目录-static 链接静态库-llibrary 连接名为 library的库文件 对于“-c”、“-E”、“-o”、“-S”选项在前一小节中已经讲解了其使用方法,在此主要讲解另外两个非常常用的库依赖选项“-I dir”和“-L dir”。“-I dir”正如上表中所述,“-I dir”选项可以在头文件的搜索路径列表中添加 dir 目录。由于 Linux 中头文件都默认放到了“/usr/include/”目录下,因此,当用户希望添加放置在其他位置的头文件时,就可以通过“-I dir”选项来指定,这样
20、,gcc 就会到相应的位置查找对应的目录。比如在“/root/workplace/Gcc”下有两个文件:/*hello1.c*/#include int main()printf(Hello!n);return 0;/*my.h*/#include 这样,就可在 gcc 命令行中加入“-I”选项:嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org rootlocalhost Gcc gcc hello1.c I/root/workplace/Gcc/-o hello1 这样,gcc 就能够执行出正确结果。“-L dir”选项“
21、-L dir”的功能与“-I dir”类似,能够在库文件的搜索路径列表中添加 dir目录。例如有程序 hello_sq.c 需要用到目录“/root/workplace/Gcc/lib”下的一个动态库libsunq.so,则只需键入如下命令即可:rootlocalhost Gcc gcc hello_sq.c L/root/workplace/Gcc/lib lsunq o hello_sq 需要注意的是,“-I dir”和“-L dir”都只是指定了路径,而没有指定文件,因此不能在路径中包含文件名。另外值得详细解释一下的是“-l”选项,它指示 gcc 去连接库文件 libsunq.so。由于
22、在 Linux 下的库文件命名时有一个规定:必须以 l、i、b 3 个字母开头。因此在用-l选项指定链接的库文件名时可以省去 l、i、b 3 个字母。也就是说 gcc 在对“-lsunq”进行处理时,会自动去链接名为 libsunq.so 的文件。(2)告警和出错选项 gcc 的告警和出错选项如表 3.8 所示。表 3.5 gcc 总体选项列表 选 项 含 义-ansi 支持符合 ANSI标准的 C 程序-pedantic 允许发出 ANSI C 标准所列的全部警告信息 续表 选 项 含 义-pedantic-error 允许发出 ANSI C 标准所列的全部错误信息-w 关闭所有告警-Wal
23、l 允许发出 gcc 提供的所有有用的报警信息-werror 把所有的告警信息转化为错误信息,并在告警发生时终止编译过程 下面结合实例对这几个告警和出错选项进行简单的讲解。如有以下程序段:#include void main()long long tmp=1;printf(This is a bad code!n);嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org return 0;这是一个很糟糕的程序,读者可以考虑一下有哪些问题?“-ansi”该选项强制 gcc 生成标准语法所要求的告警信息,尽管这还并不能保证所有没有警告
24、的程序都是符合 ANSI C 标准的。运行结果如下所示:rootlocalhost Gcc#gcc ansi warning.c o warning warning.c:在函数“main”中:warning.c:7 警告:在无返回值的函数中,“return”带返回值 warning.c:4 警告:“main”的返回类型不是“int”可以看出,该选项并没有发现“long long”这个无效数据类型的错误。“-pedantic”允许发出 ANSI C 标准所列的全部警告信息,同样也保证所有没有警告的程序都是符合 ANSI C 标准的。其运行结果如下所示:rootlocalhost Gcc#gcc
25、pedantic warning.c o warning warning.c:在函数“main”中:warning.c:5 警告:ISO C90 不支持“long long”warning.c:7 警告:在无返回值的函数中,“return”带返回值 warning.c:4 警告:“main”的返回类型不是“int”可以看出,使用该选项查看出了“long long”这个无效数据类型的错误。“-Wall”允许发出 gcc 能够提供的所有有用的报警信息。该选项的运行结果如下所示:rootlocalhost Gcc#gcc Wall warning.c o warning warning.c:4 警告
26、:“main”的返回类型不是“int”warning.c:在函数“main”中:warning.c:7 警告:在无返回值的函数中,“return”带返回值 warning.c:5 警告:未使用的变量“tmp”使用“-Wall”选项找出了未使用的变量 tmp,但它并没有找出无效数据类型的错误。另外,gcc 还可以利用选项对单独的常见错误分别指定警告,有关具体选项的含义感兴趣的读者可以查看 gcc 手册进行学习。(3)优化选项 gcc 可以对代码进行优化,它通过编译选项“-On”来控制优化代码的生成,其中n 是一个代表优化级别的整数。对于不同版本的 gcc 来讲,n 的取值范围及其对应的优化效果可
27、能并不完全相同,比较典型的范围是从 0 变化到 2 或 3。嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org 不同的优化级别对应不同的优化处理工作。如使用优化选项“-O”主要进行线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。使用优化选项“-O2”除了完成所有“-O1”级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。选项“-O3”则还包括循环展开和其他一些与处理器特性相关的优化工作。虽然优化选项可以加速代码的运行速度,但对于调试而言将是一个很大的挑战。因为代
28、码在经过优化之后,原先在源程序中声明和使用的变量很可能不再使用,控制流也可能会突然跳转到意外的地方,循环语句也有可能因为循环展开而变得到处都有,所有这些对调试来讲都将是一场噩梦。所以笔者建议在调试的时候最好不使用任何优化选项,只有当程序在最终发行的时候才考虑对其进行优化。(4)体系结构相关选项 gcc 的体系结构相关选项如表 3.6 所示。表 3.6 gcc 体系结构相关选项列表 选 项 含 义-mcpu=type 针对不同的 CPU 使用相应的 CPU 指令。可选择的 type 有 i386、i486、pentium 及 i686-mieee-fp 使用 IEEE 标准进行浮点数的比较-mn
29、o-ieee-fp 不使用 IEEE 标准进行浮点数的比较-msoft-float 输出包含浮点库调用的目标代码-mshort 把 int 类型作为 16 位处理,相当于 short int-mrtd 强行将函数参数个数固定的函数用 ret NUM 返回,节省调用函数的一条指令 这些体系结构相关选项在嵌入式的设计中会有较多的应用,读者需根据不同体系结构将对应的选项进行组合处理。在本书后面涉及到具体实例会有针对性的讲解。3.3 gdb 调试器调试器 调试是所有程序员都会面临的问题。如何提高程序员的调试效率,更好更快地定位程序中的问题从而加快程序开发的进度,是大家共同面对的。就如读者熟知的Wind
30、ows 下的一些调试工具,如 VC 自带的如设置断点、单步跟踪等,都受到了广大用户的赞赏。那么,在 Linux 下有什么很好的调试工具呢?本文所介绍的gdb调试器是一款GNU开发组织并发布的UNIX/Linux下的程序调试工具。虽然,它没有图形化的友好界面,但是它强大的功能也足以与微软的 VC 工具等媲美。下面就请跟随笔者一步步学习 gdb 调试器。3.3.1 gdb 使用流程使用流程 这里给出了一个短小的程序,由此带领读者熟悉一下 gdb 的使用流程。建议读者能够实际动手操作。首先,打开 Linux 下的编辑器 vi,编辑如下代码(由于为了更好地熟悉 gdb 的操作,笔者在此使用 vi 编辑
31、,希望读者能够参见 3.3 节中对 vi 的介绍,并熟练使用 vi)。嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org /*test.c*/#include int sum(int m);int main()int i,n=0;sum(50);for(i=1;i=50;i+)n+=i;printf(The sum of 1-50 is%d n,n);int sum(int m)int i,n=0;for(i=1;i=m;i+)n+=i;printf(The sum of 1-m is%dn,n);在保存退出后首先使用 gcc
32、 对 test.c 进行编译,注意一定要加上选项“-g”,这样编译出的可执行代码中才包含调试信息,否则之后 gdb 无法载入该可执行文件。rootlocalhost Gdb#gcc-g test.c-o test 虽然这段程序没有错误,但调试完全正确的程序可以更加了解 gdb 的使用流程。接下来就启动 gdb 进行调试。注意,gdb 进行调试的是可执行文件,而不是如“.c”的源代码,因此,需要先通过 gcc 编译生成可执行文件才能用 gdb 进行调试。rootlocalhost Gdb#gdb test GNU Gdb Red Hat Linux(6.3.0.0-1.21rh)Copyrigh
33、t 2004 Free Software Foundation,Inc.GDB is free software,covered by the GNU General Public License,and you are welcome to change it and/or distribute copies of it under certain conditions.Type show copying to see the conditions.嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org There is abs
34、olutely no warranty for GDB.Type show warranty for details.This GDB was configured as i386-redhat-linux-gnu.Using host libthread_db library/lib/libthread_db.so.1.(gdb)可以看出,在 gdb 的启动画面中指出了 gdb 的版本号、使用的库文件等信息,接下来就进入了由“(gdb)”开头的命令行界面了。(1)查看文件 在 gdb 中键入“l”(list)就可以查看所载入的文件,如下所示:(gdb)l 1#include 2 int su
35、m(int m);3 int main()4 5 int i,n=0;6 sum(50);7 for(i=1;i=50;i+)8 9 n+=i;10 (gdb)l 11 printf(The sum of 150 is%d n,n);12 13 14 int sum(int m)15 16 int i,n=0;17 for(i=1;i=m;i+)18 n+=i;19 printf(The sum of 1m is=%dn,n);20 可以看出,gdb 列出的源代码中明确地给出了对应的行号,这样就可以大大地方便代码的定位。(2)设置断点 设置断点是调试程序中是一个非常重要的手段,它可以使程序到一
36、定位置暂停它的运行。因此,程序员在该位置处可以方便地查看变量的值、堆栈情况等,从而找出代码的症结所在。嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org 在 gdb 中设置断点非常简单,只需在“b”后加入对应的行号即可(这是最常用的方式,另外还有其他方式设置断点)。如下所示:(gdb)b 6 Breakpoint 1 at 0 x804846d:file test.c,line 6.要注意的是,在 gdb 中利用行号设置断点是指代码运行到对应行之前将其停止,如上例中,代码运行到第 5 行之前暂停(并没有运行第 5 行)。(3)
37、查看断点情况 在设置完断点之后,用户可以键入“info b”来查看设置断点情况,在 gdb 中可以设置多个断点。(gdb)info b Num Type Disp Enb Address What 1 breakpoint keep y 0 x0804846d in main at test.c:6 (4)运行代码 接下来就可运行代码了,gdb 默认从首行开始运行代码,可键入“r”(run)即可(若想从程序中指定行开始运行,可在 r 后面加上行号)。(gdb)r Starting program:/root/workplace/Gdb/test Reading symbols from sha
38、red object read from target memory.done.Loaded system supplied DSO at 0 x5fb000 Breakpoint 1,main()at test.c:6 6 sum(50);可以看到,程序运行到断点处就停止了。(5)查看变量值 在程序停止运行之后,程序员所要做的工作是查看断点处的相关变量值。在 gdb中只需键入“p”变量值即可,如下所示:(gdb)p n$1=0(gdb)p i$2=134518440 在此处,为什么变量“i”的值为如此奇怪的一个数字呢?原因就在于程序是在断点设置的对应行之前停止的,那么在此时,并没有把“i”的
39、数值赋为零,而只是一个随机的数字。但变量“n”是在第四行赋值的,故在此时已经为零。嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org(6)单步运行 单步运行可以使用命令“n”(next)或“s”(step),它们之间的区别在于:若有函数调用的时候,“s”会进入该函数而“n”不会进入该函数。因此,“s”就类似于 VC等工具中的“step in”,“n”类似与 VC 等工具中的“step over”。它们的使用如下所示:(gdb)n The sum of 1-m is 1275 7 for(i=1;i=50;i+)(gdb)s s
40、um(m=50)at test.c:16 16 int i,n=0;可见,使用“n”后,程序显示函数 sum的运行结果并向下执行,而使用“s”后则进入到 sum函数之中单步运行。(7)恢复程序运行 在查看完所需变量及堆栈情况后,就可以使用命令“c”(continue)恢复程序的正常运行了。这时,它会把剩余还未执行的程序执行完,并显示剩余程序中的执行结果。以下是之前使用“n”命令恢复后的执行结果:(gdb)c Continuing.The sum of 1-50 is:1275 Program exited with code 031.可以看出,程序在运行完后退出,之后程序处于“停止状态”。3.
41、3.2 gdb 基本命令基本命令 gdb 的命令可以通过查看 help 进行查找,由于 gdb 的命令很多,因此 gdb 的 help将其分成了很多种类(class),用户可以通过进一步查看相关 class 找到相应命令。如下所示:(gdb)help List of classes of commands:aliases-Aliases of other commands breakpoints-Making program stop at certain points data-Examining data files-Specifying and examining files inter
42、nals-Maintenance commands 嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org Type help followed by a class name for a list of commands in that class.Type help followed by command name for full documentation.Command name abbreViations are allowed if unambiguous.上述列出了 gdb 各个分类的命令,注意底部的加粗部分说明其
43、为分类命令。接下来可以具体查找各分类种的命令。如下所示:(gdb)help data Examining data.List of commands:call-Call a function in the program delete display-Cancel some expressions to be displayed when program stops delete mem-Delete memory region disable display-Disable some expressions to be displayed when program stops Type he
44、lp followed by command name for full documentation.Command name abbreViations are allowed if unambiguous.至此,若用户想要查找 call 命令,就可键入“help call”。(gdb)help call Call a function in the program.The argument is the function name and arguments,in the notation of the current working language.The result is prin
45、ted and saved in the value history,if it is not void.当然,若用户已知命令名,直接键入“help command”也是可以的。gdb 中的命令主要分为以下几类:工作环境相关命令、设置断点与恢复命令、源代码查看命令、查看运行数据相关命令及修改运行参数命令。以下就分别对这几类的命令进行讲解。1工作环境相关命令工作环境相关命令 gdb 中不仅可以调试所运行的程序,而且还可以对程序相关的工作环境进行相应的设定,甚至还可以使用 shell 中的命令进行相关的操作,其功能极其强大。表 3.7 所示为 gdb 常见工作环境相关命令。表 3.7 gdb 工作
46、环境相关命令 嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org 命 令 格 式 含 义 set args 运行时的参数 指定运行时参数,如 set args 2 show args 查看设置好的运行参数 path dir 设定程序的运行路径 show paths 查看程序的运行路径 set enVironment var=value 设置环境变量 show enVironment var 查看环境变量 cd dir 进入到 dir 目录,相当于 shell 中的 cd 命令 pwd 显示当前工作目录 shell comman
47、d 运行 shell 的 command 命令 2设置断点与恢复命令设置断点与恢复命令 gdb 中设置断点与恢复的常见命令如表 3.8 所示。表 3.8 gdb 设置断点与恢复相关命令 命 令 格 式 含 义 bnfo b 查看所设断点 break 行号或函数名 设置断点 tbreak 行号或函数名 设置临时断点,到达后被自动删除 delete 断点号 删除指定断点,其断点号为“info b”中的第一栏。若缺省断点号则删除所有断点 disable 断点号 停止指定断点,使用“info b”仍能查看此断点。同 delete 一样省断点号则停止所有断点 enable 断点号 激活指定断点,即激活被
48、 disable 停止的断点 condition 断点号 修改对应断点的条件 ignore 断点号 在程序执行中,忽略对应断点 num 次 step 单步恢复程序运行,且进入函数调用 next 单步恢复程序运行,但不进入函数调用 finish 运行程序,直到当前函数完成返回 c 继续执行函数,直到函数结束或遇到新的断点 由于设置断点在 gdb 的调试中非常重要,所以在此再着重讲解一下 gdb 中设置断点的方法。gdb 中设置断点有多种方式:其一是按行设置断点,设置方法在 3.3.1 节已经指出,在此就不重复了。另外还可以设置函数断点和条件断点,在此结合上一小节的代码,具体介绍后两种设置断点的方
49、法。函数断点 嵌入式 Linux 操作系统第 3 章 嵌入式 Linux 编程环境 华清远见嵌入式学院:www.embedu.org gdb 中按函数设置断点只需把函数名列在命令“b”之后,如下所示:(gdb)b sum Breakpoint 1 at 0 x80484ba:file test.c,line 16.(gdb)info b Num Type Disp Enb Address What 1 breakpoint keep y 0 x080484ba in sum at test.c:16 要注意的是,此时的断点实际是在函数的定义处,也就是在 16 行处(注意第 16行还未执行)。条
50、件断点 gdb 中设置条件断点的格式为:b 行数或函数名 if 表达式。具体实例如下所示:(gdb)b 8 if i=10 Breakpoint 1 at 0 x804848c:file test.c,line 8.(gdb)info b Num Type Disp Enb Address What 1 breakpoint keep y 0 x0804848c in main at test.c:8 stop only if i=10(gdb)r Starting program:/home/yul/test The sum of 1-m is 1275 Breakpoint 1,main(