📄 00000009.htm
字号:
清单 13-4 一个有错误的 C 源程序 test.c <BR>――――――――――――――――――――――――――――――――――――――― <BR>#include <stdio.h> <BR>#include <stdlib.h> <BR> <BR>static char buff [256]; <BR>static char* string; <BR>int main () <BR>{ <BR> <BR> printf ("Please input a string: "); <BR> gets (string); <BR> <BR> printf ("\nYour string is: %s\n", string); <BR>} <BR>――――――――――――――――――――――――――――――――――――――― <BR>上面这个程序非常简单,其目的是接受用户的输入,然后将用户的输入打印出来。该 <BR>程序使用了一个未经过初始化的字符串地址 string,因此,编译并运行之后,将出现 <BR>Segment Fault 错误: <BR>[WeiYM@versa gcc]$ gcc -o test -g test.c <BR>[WeiYM@versa gcc]$ ./test <BR>Please input a string: asfd <BR>Segmentation fault (core dumped) <BR>为了查找该程序中出现的问题,我们利用 gdb,并按如下的步骤进行: <BR>1.运行 gdb test 命令,装入 test 可执行文件; <BR>2.执行装入的 test 命令: <BR>(gdb) run <BR>Starting program: /home/WeiYM/projects/study/gcc/test <BR>Please input a string: abcd <BR> <BR>Program received signal SIGSEGV, Segmentation fault. <BR>0x4006a7da in _IO_gets (buf=0x0) at iogets.c:55 <BR>iogets.c:55: No such file or directory. <BR>3.使用 where 命令查看程序出错的地方: <BR> (gdb) where <BR>#0 0x4006a7da in _IO_gets (buf=0x0) at iogets.c:55 <BR>#1 0x8048413 in main () at test.c:11 <BR>#2 0x40030cb3 in __libc_start_main (main=0x80483f8 <main>, argc=1, <BR> argv=0xbffffca4, init=0x80482bc <_init>, fini=0x804845c <_fini>, <BR> rtld_fini=0x4000a350 <_dl_fini>, stack_end=0xbffffc9c) <BR> at ../sysdeps/generic/libc-start.c:78 <BR>where 命令的输出显示了函数的调用顺序,最近一次函数调用,即 #0 调用是 C 库 <BR>函数 gets。该函数从 test.c 的第 11 行处调用(main 函数)。 <BR>4.利用 list 命令查看调用 gets 函数附近的代码: <BR>(gdb) list test.c:11 <BR>6 <BR>7 int main () <BR>8 { <BR>9 <BR>10 printf ("Please input a string: "); <BR>11 gets (string); <BR>12 <BR>13 printf ("\nYour string is: %s\n", string); <BR>14 } <BR>15 <BR>5.唯一能够导致 gets 函数出错的因素就是变量 string。用 print 命令查看 string <BR>的值: <BR>(gdb) print string <BR>$1 = 0x0 <BR>显然,为 gets 函数传递了一个空指针,这就是程序的错误所在。这是因为 string 是 <BR>一个全局变量,运行时初始化为 0,即空指针。 <BR>6.在 gdb 中,我们可以直接修改变量的值,只要将 string 取一个合法的指针值就 <BR>可以了,为此,我们在第 11 行处设置断点: <BR>(gdb) break 11 <BR>Breakpoint 1 at 0x8048408: file test.c, line 11. <BR>(gdb) run <BR>The program being debugged has been started already. <BR>Start it from the beginning? (y or n) y <BR>Starting program: /home/WeiYM/projects/study/gcc/test <BR> <BR>Breakpoint 1, main () at test.c:11 <BR>11 gets (string); <BR>7.程序重新运行到第 11 行处停止,这时,我们可以用 set variable 命令修改 string <BR>的取值: <BR>(gdb) set var string=buff <BR>8.然后继续运行,将看到正确的程序运行结果: <BR>(gdb) cont <BR>Continuing. <BR>Please input a string: abcd <BR> <BR>Your string is: abcd <BR> <BR>Program exited with code 026. <BR>上面的例子足以说明 gdb 的一般使用方法,当然,gdb 的命令很多,还可用来调试 <BR>多线程程序。这些命令的使用,需要读者在实践中学习并掌握。 <BR>13.3.5 版本控制工具 <BR>在小型软件的开发过程中,利用 make 工具可自动完成一些编译工作。如果涉及到的 <BR>开发人员不多,代码的维护是简单的。人们通常利用备份和强制性的代码注释来维护源程 <BR>序的修改。但在大型项目中,开发人员和代码规模非常大的情况下,就有必要采用专门的 <BR>版本控制软件来维护代码的修订。在 Microsoft 的开发工具中,有一个称为 SourceSafe 的 <BR>软件,专门用来进行版本控制,在 PowerBuilder 这样的大型开发工具中,也通常有内置 <BR>的版本控制系统。在 Linux 上,通常使用的版本控制系统叫 RCS,即 Revision Control <BR>System(修订控制系统)。 <BR>利用版本控制系统,开发人员能够在需要时恢复某个文件的特定版本或修订。在使用 <BR>版本控制系统时,开发人员对一个文件的修改工作按如下的步骤进行: <BR>1.当开发人员有一个初始的源文件版本时,将该文件归档到版本控制系统中。 <BR>2.当开发人员需要对某个文件进行修改时,首先要获得当前版本的一个拷贝。在某 <BR>个开发人员获得该文件的一个拷贝时,版本控制系统将确保其他人不能获得该文件。 <BR>3.当修改完源文件,并经过测试之后,开发人员将该文件保存为一个新的版本。 <BR>4.其后需要修改该文件时,将始终在该文件的最新版本的基础上进行修改。 <BR>为此,RCS 提供了许多工具帮助维护源代码的修订,主要的工具见表 13-5。 <BR>表 13-5 RCS 的主要工具 <BR>工具名称 <BR>功能 <BR>ci <BR>建立某个文件的新修订或将某个工作文件添加到 RCS 文件中。 <BR>co <BR>为只读目的获取某个文件的一个工作版本。(co -l 可提供一个工作文件并锁定原有 <BR>的文件,这样就可以修改工作文件。) <BR>ident <BR>在文件中搜索标识符。 <BR>merge <BR>将两个文件合并成为第三个文件。 <BR>rcsdiff <BR>就工作文件和 RCS 维护的文件进行比较。 <BR>rcsmerge <BR>合并某个文件的不同版本。 <BR>rlog <BR>查看某个文件的修改日志。 <BR> <BR>限于篇幅不能详细讲解 RCS 的使用,详细信息可参阅 rcsintro(1)手册页以及相 <BR>关帮助信息。 <BR>13.3.6 Perl 简介 <BR>Linux 为开发人员提供了广阔的活动舞台。开发人员不仅能够利用 C/C++、Fortran、 <BR>Pacal、Lisp 等多种编程语言编写程序,而且能够使用各种脚本语言编写程序,其中包括 <BR>Shell 脚本、Perl 脚本、Tcl/Tk 脚本等。通常说来,脚本语言就是一种编程语言,但它 <BR>更加贴近自然语言,具有简单、方便的特点,并且在某些方面,比起传统的编程语言来说 <BR>更加有优势。 <BR>本小节将简单描述在 Linux 中广为使用的脚本语言 Perl。Perl,即 Practical <BR>Extraction Report Language(实用析取报表语言),由 Larry Wall 创立,可用来从文 <BR>本文件中析取信息,并利用这些信息建立报表。由于 Perl 和 Linux 一样,也是自由软 <BR>件,因此,Perl 在各种计算机系统中广为流传。各种 Linux 商业发行版本中均包含有 <BR>Perl。 <BR>13.3.6.1 Perl 脚本的执行 <BR>和传统的编译语言不同,Perl 脚本一般是一些文本文件,由 perl 程序解释并执行 <BR>Perl 脚本。例如,下面是一个简单的 Perl 脚本: <BR>#!/usr/bin/perl <BR># This is a comment. <BR>print "Hello, World!\n" <BR>该脚本的第一行利用 #! 指定了脚本的解释程序为 /usr/bin/perl,第二行是一个注 <BR>释行,第三行打印“Hello, World!”。 <BR>执行该脚本之前,首先要将脚本文件设置为可执行模式。如果脚本名称为 hello.pl <BR>(.pl 一般是 Perl 脚本的后缀名),则使用如下的命令: <BR>$ chmod +x hellol.pl <BR>然后可在命令行直接执行 hello.pl: <BR>$ ./hello.pl <BR>实际上,Linux 将按如下命令执行脚本: <BR>/usr/bin/perl ./hello.pl <BR>13.3.6.2 Perl 的基本语法 <BR>Perl 包含有与其他语言一样的共同特色: <BR>? 用来保存不同类型数据的变量。 <BR>? 利用运算符将变量组合而成的表达式。 <BR>? 执行动作的表达式。 <BR>? 可控制语句执行路线的流控制语句。 <BR>? 划分功能,提供可重用性的函数(子例程或例程)。 <BR>Perl 程序的书写形式是自由的,和 C 类似,每个 Perl 语句以分号(;)结束,# 代 <BR>表一个注释行,Perl 也用与 C 一样的大括号({...})来定义语句组。 <BR>下面的小节讲述 Perl 变量、运算符和表达式、语句、流控制以及其他的特性。 <BR>13.3.6.3 变量 <BR>在 Perl 程序中,不必显示定义变量,所有的变量以 @、$ 或 % 打头,分别代表了 Perl <BR>的三种变量类型。 <BR>? 标量型变量(Scalar Variable)。标量型变量定义了基本的数据类型,包括整 <BR>数、浮点数和字符串。标量型变量由 $ 字符开头: <BR>$title = "Linux And Windows NT"; <BR>$count = 10; <BR>? 数组型变量(Array Variable)。数组型变量是标量型变量的集合,数组型变量 <BR>的前缀是 @,如下所示: <BR>@commands = ("ls", "dir", "cd", "rm", "mv"); <BR>@length = (2, 3, 2, 2, 2); <BR>可通过类似 C 语言的下标方法访问数组中的元素
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -