实验五Linux开发工具的使用(一) |
您所在的位置:网站首页 › linux使用gcc编译c语言程序实验结论分析 › 实验五Linux开发工具的使用(一) |
一、实验目的 1.掌握C语言编译的基本方法。 2.掌握gdb调试工具的基本用法。 二、实验注意事项 实验室内的实验环境与系统是共用设施,请不要在系统内做对系统或对其他用户不安全的事情。 要求每个同学登录后系统后,要在自己的家目录下创建一个属于自己的子目录(以自己(拼音)名字或学号)。以后所有工作都要在自己的目录内进行。建议以后的实验都在同台计算机上做,这样可以保持连续性。 用户要按通常实验要认真书写实验报告。 三、实验内容及步骤 1. 用gcc带不同参数编译下列hello.c程序。 #include int main() { printf(”Hello World!\n”); return 0; } (1)只作预处理,生成hello.i,相应命令为: gcc -E hello.c -o hello.i (2)只进行编译,不做汇编,生成汇编代码,命令为: gcc -S hello.c (3)只进行汇编,不做连接,生成目标代码,命令为: gcc -c hello.c (4)以默认方式生成可执行程序a.out,命令为: gcc hello.c (5)生成可执行程序hello,命令为: gcc hello.c -o hello 2.Linux下gcc的生成和使用动态库和静态库 程序1: hello.h #ifndef HELLO_H #define HELLO_H void hello(const char *name); #endif 程序2:hello.c #include void hello(const char *name) { printf("Hello %s!\n", name); } 程序3:main.c #include "hello.h" int main() { hello("everyone"); return 0; } 注意:这个时候,我们编译好的hello.o是无法通过gcc –o 编译的,这个道理非常简单,hello.c是一个没有main函数的.c程序,因此不够成一个完整的程序,如果使用gcc –o 编译并连接它,GCC将报错。 无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过gcc先编译成.o文件。 这个时候我们有三种思路: 1) 通过编译多个源文件,直接将目标代码合成一个.o文件。 2) 通过创建静态链接库libmyhello.a,使得main函数调用hello函数时可调用静态链接库。 3) 通过创建动态链接库libmyhello.so,使得main函数调用hello函数时可调用动态链接库。 思路一:编译多个源文件 命令为: 思路二:静态链接库 静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,需要注意这点。创建静态库用ar命令。 在系统提示符下键入以下命令将创建静态库文件libmyhello.a。 # ar rcs libmyhello.a hello.o 在主程序main中直接调用公用函数hello,生成目标程序hello的命令为: 删除静态库文件试试公用函数hello,看是否真的连接到目标文件 hello,命令为: 思路三、动态链接库(共享函数库) 静态链接库的一个缺点是,如果我们同时运行了许多程序,并且它们使用了同一个库函数,这样,在内存中会大量拷贝同一库函数。这样,就会浪费很多珍贵的内存和存储空间。使用了共享链接库的Linux就可以避免这个问题。 共享函数库和静态函数在同一个地方,只是后缀有所不同。比如,在一个典型的Linux系统,标准的共享数序函数库是/usr/lib/libm.so。 当一个程序使用共享函数库时,在连接阶段并不把函数代码连接进来,而只是链接函数的一个引用。最终的函数导入内存开始真正执行时,函数引用被解析,共享函数库的代码才真正导入到内存中。这样,共享链接库的函数就可以被许多程序同时共享,并且只需存储一次就可以了。共享函数库的另一个优点是,它可以独立更新,与调用它的函数毫不影响。 在系统提示符下键入以下命令得到动态库文件libmyhello.so # gcc -shared -fPIC -o libmyhello.so hello.o “PIC”命令行标记告诉GCC产生的代码不要包含对函数和变量具体内存位置的引用,这是因为现在还无法知道使用该消息代码的应用程序会将它连接到哪一段内存地址空间。这样编译出的hello.o可以被用于建立共享链接库。建立共享链接库只需要用GCC的”-shared”标记即可。 运行gcc命令生成目标文件,命令为: 错误提示,找不到动态库文件libmyhello.so。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。有多种方法可以解决, (1)我们将文件 libmyhello.so复制到目录/usr/lib中,再试试。 # mv libmyhello.so /usr/lib # ./hello 成功! (2)既然连接器会搜寻LD_LIBRARY_PATH所指定的目录,那么我们可以将这个环境变量设置成当前目录: 先执行: export LD_LIBRARY_PATH=`pwd` 再执行: ./hello 成功! LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。 3. 使用gdb调试下列程序,练习gdb命令。 #include #include #include void my_print (char *string) { printf ("The string is %s\n", string); } void my_print2 (char *string) { char *string2; int size, i; size = strlen (string); string2 = (char *) malloc (size + 1); for (i = 0; i < size; i++) string2[size - i] = string[i]; string2[size+1] = `\0'; printf ("The string printed backward is %s\n", string2); } int main () { char my_string[] = "hello there"; my_print (my_string); my_print2 (my_string); }
用下面的命令编译它: gcc –g greeting.c -o greeting
这个程序执行时显示如下结果: The string is hello there The string printed backward is
输出的第一行是正确的, 但第二行打印出的东西并不是我们所期望的。我们所设想的输出应该是: The string printed backward is ereht olleh 由于某些原因, my_print2 函数没有正常工作。让我们用 gdb 看看问题究竟出在哪儿, 先键入如下命令: gdb greeting 注意: 记得在编译 greeting 程序时把调试选项打开。 如果你在输入命令时忘了把要调试的程序作为参数传给 gdb , 你可以在 gdb 提示符下用 file 命令来载入它: (gdb) file greeting 这个命令将载入 greeting 可执行文件就象你在 gdb 命令行里装入它一样。 这时你能用 gdb 的 run 命令来运行 greeting 了。 当它在 gdb 里被运行后结果大约会象这样: (gdb) run Starting program: /home/student/greeting The string is hello there The string printed backward is Program exited normally. 这个输出和在 gdb 外面运行的结果一样。 问题是, 为什么反序打印没有工作? 为了找出症结所在, 我们可以在 my_print2 函数的 for 语句后设一个断点, 具体的做法是在 gdb 提示符下键入 list 命令三次, 列出源代码. 技巧: 在 gdb 提示符下按回车健将重复上一个命令. 第一次键入 list 命令的输出如下: 1 #include 2 #include 3 #include 4 void my_print (char *string) 5 { 6 printf ("The string is %s\n", string); 7 } 8 void my_print2 (char *string) 9 { *string2;如果按下回车,gdb将再次执行一次list命令,给出下列输出; 11 int size, i; 12 size = strlen (string); 13 string2 = (char *) malloc (size + 1); 14 for (i = 0; i < size; i++) 15 string2[size - i] = string[i]; 16 string2[size+1] = ‘\0'; 17 printf ("The string printed backward is %s\n", string2); 18 } 19 int main () 20 { 再按一次回车将列出 greeting 程序的剩余部分: 21 char my_string[] = "hello there"; 22 my_print (my_string); 23 my_print2 (my_string); 24 return 0; 25 } 根据列出的源程序, 你能看到要设断点的地方在第15行, 在 gdb 命令行提示符下键入如下命令设置断点: (gdb) break 15 gdb 将作出如下的响应: Breakpoint 1 at 0x139: file greeting.c, line 15 (gdb) 现在再键入 run 命令, 将产生如下的输出: Starting program: /home/student/greeting The string is hello there Breakpoint 1, my_print2 (string = 0xbfffdc4 "hello there") at greeting.c :15 15 string2[size-i]=string[i] 这时可通过设置一个观察点,观察 string2[size - i] 变量的值来看错误是怎样产生的, 做法是键入: (gdb) watch string2[size - i] gdb 将作出如下回应: Watchpoint 2: string2[size - i]
现在可以用 next 命令来一步步的执行 for 循环了: (gdb) next 经过第一次循环后, gdb 告诉我们 string2[size - i] 的值是 `h`. gdb 用如下的显示来告诉你这个信息: Watchpoint 2, string2[size - i] Old value = 0 `\000' New value = 104 `h' my_print2(string = 0xbfffdc4 "hello there") at greeting.c:14 14 for (i=0; i char *string2; int size,i; size=strlen(string); string2=(char*)malloc(size + 1); for(i=0;i int i ,s=0; double ave; *min=*max=array[0]; for(i=1;i |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |