1 / 37

Linux 下的 C 程序编程

Linux 下的 C 程序编程. 主要内容. GCC 编译器. GDB 调试器. 一、 GCC 编译器 1 、 GCC 是什么. GCC ( the GNU Complier Collection,GNU 编译工具合集)。包括预编译( cpp )、编译( gcc ),与 make 、连接( ld )、调试( gdb )等多个编译过程的常用工具一起组成 GNU 开发工具链。

xander
Download Presentation

Linux 下的 C 程序编程

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Linux下的C程序编程

  2. 主要内容 GCC编译器 GDB调试器

  3. 一、GCC编译器1、GCC是什么 GCC(the GNU Complier Collection,GNU编译工具合集)。包括预编译(cpp)、编译(gcc),与make、连接(ld)、调试(gdb)等多个编译过程的常用工具一起组成GNU开发工具链。 • GCC1.0于1987年5月发布,历经20余年的发展,已经成为一款功能强大的世界级优秀编译工具。支持多种语言的编译,包括C、C++、Ada、Fortran、Java等,并且包含这些语言相应的开发支持库(可到GCC官网http://gcc.gnu.org/下载所用开发语言的编译器,gcc、g++、gcc-java等)。

  4. GCC的优点 • 与其他一些软件公司出品的编译器比较,GCC生成的可执行文件具有代码长度短、执行效率高等特点。 • 具有较强的灵活性和高度的可移植性。安装GCC时做些简单设置或对GCC源码进行少量修改,就可以使GCC完成在不同指令系统的交叉编译,极大地方便了嵌入式设备的软件开发。 • 可方便地与其他软件和协议对接。

  5. GCC通过后缀来区别输入文件的类型,集成C、C++、JAVA等多种语言编译器。是符合ANSI C标准的多平台编译器。 • .c C语言源代码文件。 • .h 程序所包含的头文件。 • .o 编译后的目标文件。 • .C、.cpp、.cc或.cxx C++源代码文件。 • ii 己经预处理过的C++源代码文件。 • .i 已经预处理过的C源代码文件。 • .s 汇编语言源代码文件。 • .S 经过预编译的汇编语言源代码文件。 • a 由目标文件构成的档案库文件。

  6. 网络支持下的命令安装 sudo apt-get install gcc sudo apt-get install build-essential gcc –v (或gcc --version) 类似的 sudo apt-get install g++ sudo apt-get install gcj • 源代码安装GCC(选看) • find / -name gcc* • find / -name g++* • find / -name gcj*

  7. 2、gcc工作流程 • gcc是c语言程序编译器。一个C语言程序编译过程如下: • 编辑:写源码 • 预处理:系统加载头文件和展开宏,仅对文本信息处理,是编译前的准备、整理。 • 编译:将C语言转换为对应的计算机机器码,生成二进制文件。但若有多个模块,此时的文件还不能执行,因为各模块还相对独立,相互使用的地方还是标记。 • 链接:将模块合成一个可执行的整体。 • gcc通过分别调用预处理、编译、链接工具,自动完成C程序的编译工作。

  8. hello world • 编辑vi hello.c #include <stdio.h> int main() { printf(“HELLO WORLD.THIS IS MY FIRST C PROGRAM”); return 0; } • 编译执行 gcc hello.c 编译生成可执行文件,结果为a.out 或 gcc –o hey hello.c 编译生成可执行文件,指定结果文件名为hey

  9. 3、基本使用 GCC有超过100个的编译选项。选项的合理使用对编译调试程序有很大作用。 • 利用优化选项告诉gcc产生更小更快的可执行文件,典型的如-O告诉gcc进行基本优化、-O2产生尽可能小、快的代码。 • 利用调试选项方便调试剖析,如-g产生能被gdb使用的调试信息。 • 更多调试选项可查阅man及其他手册或资料。

  10. gcc常用参数列表

  11. 举例 1)Vi编辑器编写代码 vi chess.c #include <stdio.h> main() { int i,j; for (i=0;i<8;i++) /*象棋棋盘图案*/ { for(j=0;j<8;j++) if((i+j)%2==0) printf("%c%c“ ; 0xa1,0xf6); /*输出黑色小方块(GB2312编码)*/ else printf(" "); printf("\n"); } printf("\n"); for(i=1;i<11;i++) /*阶梯图案*/ { for(j=1;j<=i;j++) printf("%c%c“,0xa1,0xf6); /*输出黑色小方块(GB2312编码)*/ printf("\n"); } }

  12. 2)编译 gcc chess.c –o chess • GCC给出报错信息,9:expected ’)’ before ‘’ token • 将“;”修改成“,”后存盘退出。再编译一次。注意用上下方向键可使用历史命令,减少多次输入。 3)执行 • 在图形界面中设置“终端”→“设定字符编码”选中“简体中文(GB2312)”。 • ./chess 执行看效果即可。

  13. vi main.c #include <stdio.h> void chessboard(); void stair(); main() { chessboard(); stair(); } vi chessboard.c #include <stdio.h> void chessboard() { int i,j; for (i=0;i<8;i++) { for(j=0;j<8;j++) if((i+j)%2==0) printf("%c%c",0xa1,0xf6); else printf(" "); printf("\n"); } printf("\n"); } 多个文件的编译 gcc main.c chessboard.c stair.c –o prngrap vi stair.c #include <stdio.h> void stair() { int i,j; for(i=1;i<11;i++) { for(j=1;j<=i;j++) printf("%c%c",0xa1,0xf6); printf("\n"); } printf("\n"); }

  14. 常见报错 • 语法错误: • 错误信息:文件source.c中第 n 行有语法错误(syntex error)。 • 头文件错误 • 错误信息:找不到头文件head.h ( can not find include file head.h)。 • 函数库错误 • 错误信息:链接程序找不到所需的函数库。如:ld:-lm:No such file or directory

  15. * 关于头文件与库文件 * • gcc 在编译时如何寻找所需要的头文件: • header file 的搜寻会从 -I 开始 • 然后找 gcc 的环境变量 C_INCLUDE_PATH、CPLUS_INCLUDE_PATH、OBJC_INCLUDE_PATH • 再找内定目录 /usr/include 用户空间头文件 /usr/local/include 本地头文件 /usr/src/include 内核态头文件 。。。 • gcc怎么找库函数所在的库文件 ? • 先找 -L 指定的搜索目录 如cos( ) 等函式库的选项要多加 –lm(指定libm.so库) • 再找 gcc 的环境变量 LIBRARY_PATH • 再找内定目录 /lib /usr/lib /usr/local/lib 。。。

  16. 可以用两个编译选项指定位置 如:d1目录下的a.c程序,用到d2目录下的h1.h。 gcc –o aexe a.c –I d2 (下面的dir代表一个目录名) • -I dir:指定头文件所在目录。gcc先在指定目录dir下查找头文件,然后再按常规查找。 • -L dir:gcc搜索函数所在的库文件时先在dir中找,然后才到标准库中找。

  17. 想实现某个功能,却不知道用哪个函数? • 查手册 • 《Linux函数库参考手册》(适合不知道什么功能该用什么函数,以及函数的具体使用) • man(适合知道函数名后查具体使用) • 积累 • 多读、多做 • vi中在函数名处按shift+k可看到函数说明信息 • 为什么别人对用什么函数这么有数? 上述就是答案。学会查!多积累经验!没有捷径!

  18. 4、代码管理工具make • GNU make: 编译处理较多文件时程序员就不需要每次编译都键入同样的大量的gcc命令。 利用make对包含一组文件的项目进行管理,采用增量编译,根据文件修改自动判断哪些需要重新编译,哪些利用上次结果,避免大量的重复计算,提高了编译效率。 • makefile make工具通过一种脚本文件来完成自动编译,所有编译操作写在一个文件内,方便维护编译工作,默认该文件叫makefile 。 • 该文件定义多个源文件之间的依赖关系; • 说明如何编译各个源文件并链接生成可执行文件。

  19. makefile文件一般由一种两行的脚本单元(规则)组成,简单例子:makefile文件一般由一种两行的脚本单元(规则)组成,简单例子: • vi makefile test:test.c test.h (目标文件:依赖文件) gcc test.c –o test (达成目标使用的命令,注意前要有一个tab) • make 或 make test (目标名与makefile中的要一致)

  20. 1、makefile文件语法: target:dependency_files(依赖关系) (tab)command target(具体操作) 如: guess: main.o b.o gcc main.o b.o –o guess(此句前是tab不是空格) main.o:main.c h1.h gcc –c main.c –o main.o b.o:b.c h2.h gcc –c b.c –o b.o 2、make的执行: make (默认使用当前目录下的makefile) make –f mk (指定编译使用的make文件是mk)

  21. 1.写一个自己的头文件,在头文件中定义一个变量和一个函数。1.写一个自己的头文件,在头文件中定义一个变量和一个函数。 vi my.h int a; int myfun(int x, int y) { int z; z=x*y; return z; } 2.写一个主文件, 获得用户输入的两个数,利用自己的函数得到成绩。 vi my.c #include <stdio.h> #include “my.h” int main() { int x,y,z; printf(“please input two numbers:\n”); scanf(“%d,%d”,&x,&y); z=myfun(x,y); printf(“x*y=%d”,z); return z; } 3.给自己的程序写一个makefile文件 vi mymake my:my.c gcc –o my.exe –g my.c 4.运行,测试,观察结果 make –f mymake ./my.exe echo $?

  22. 第一个目标是最终目标,目标顺序不能颠倒 定义一个功能是删除中间文件特殊目标,命名为clr 通过执行make clr,中间文件to.o会被删除

  23. 3、在makefile中使用变量(或称宏) 可方便对makefile文件进行维护。引用变量时,名字超过一个字符要加圆括号。如 ob=test.c test.h fg=-LS target:$(ob) gcc $(ob) $(fg) –o target • 练习对多个文件写makefile:可先试着用独立的gcc语句单独编译成功,再把用过的语句组织成makefile文件。

  24. vi guess.h #include "time.h" #include "stdlib.h" #include "stdio.h" #include "string.h" void guesssub(int i); typedef struct goods { char name[20]; int price; }GOODS; vi guessmain.c #include "guess.h" main() { GOODS goodslist[5]; int i; strcpy(goodslist[0].name,"钱包"); goodslist[0].price=288; strcpy(goodslist[1].name,"领带"); goodslist[1].price=320; strcpy(goodslist[2].name,"手表"); goodslist[2].price=560; strcpy(goodslist[3].name,"礼帽"); goodslist[3].price=260; strcpy(goodslist[4].name,"皮带"); goodslist[4].price=470; do { printf("\n**小游戏:猜商品价格**\n"); printf("---------------------------\n"); for(i=0;i<5;i++) printf("\t%d---%s\n",i,goodslist[i].name); printf("---------------------------\n"); printf("请选择一个上述商品的编号进行输入:"); scanf("%d",&i); guesssub(goodslist[i].price); printf("还想继续吗?y--继续 任意键--结束游戏:"); getchar(); }while(getchar()=='y'); } * 举例2,猜数字游戏 vi guesssub.c #include "guess.h" void guesssub(int i) { char c; time_t a,b; double var; int guess; srand(time(NULL)); a=time(NULL); printf("\n开始啰!\n请输入价格:"); scanf("%d",&guess); while(guess!=i) { if(guess>i) printf("高了!请重输价格:"); else printf("低了!请重输价格:"); scanf("%d",&guess); } b=time(NULL); var=difftime(b,a); printf("\n\nOK!所猜商品价格正是 %d元\n",i); printf(" 用时 %6.3f 秒\n\n",var); if(var<20) printf(" **你相当聪明!**\n\n“"); else if(var<35) printf(" **你表现一般!** \n\n"); else printf("**你需要提高水平,加油! **\n\n"); }

  25. 二、GDB调试器 1、GDB介绍 • GDB调试器主要用于调试可执行文件,这个文件必须提供调试版本,包含调试信息。 • 所以,编译程序时一定用调试选项使生成的可执行文件内包含调试信息,常用-g。 • 调试信息包含程序里每个变量的类型和在可执行文件里的地址映射及行号。 • 主要功能: • 监视程序中变量的值 • 设置断点 • 逐行执行代码

  26. gdb常用参数列表

  27. 初始源代码的输入 编译带调试信息的可执行文件 启动GDB开始调试 运用GDB命令,分析源代码执行 退出GDB 用vi修改调试中发现的源代码错误 2、使用举例:调试一个计算1~50和1~100累加值的程序。

  28. (1)vi tst.c,打开vi编辑器,编辑tst.c源程序文件 #include <stdio.h> int sum(int n); main() { int i,result=0; for(i=1;i<=50;i++) result+=i; printf("result[1-50]=%d\n",result); printf("result[1-100]=%d\n",sum(100)); } int sum(int n) { int i ,sum; for(i=1;i<=n;i++) sum+=i; return sum; }

  29. (2)编译tst.c并运行tst程序 • 编译:gcc tst.c –o tst • 运行:./tst gcc编译时无报错,表明编译通过。但运行tst时,第一行结果result[1-50]=1275是正确的,第二行结果result[1-100]=1244812206与预想不符

  30. 查看文件 程序的关键断点。 按回车键 按回车键 (3)调试 • 输入命令:gcc -g tst.c -o tstsum • 启动调试:gdb tstsum • 在gdb下进行调试过程用到许多基本gdb命令,一般都只写首字母即可。 • 键入“l”(list)查看gdb载入文件tstsm的源代码。按回车则重复上一次操作。

  31. 在第18行设置断点 键入”info b”查看设置断点的情况;输入命令“d 断点号”删除(delete)断点 GDB中键入“r”(run),程序从首行运行到断点前一句,在断点处暂停。

  32. 在GDB中键入“p(print) 变量名”命令查看断点处的相关变量值 在gdb中输入命令“n”(next),采用单步运行方式继续往下执行程序 • 在gdb中输入命令“c”(continue)把剩余还未执行的程序执行完 • 键入“q”(quit),退出GDB调试,返回终端的系统提示符。 本例子错误在sum函数中未对sum变量初始化。

  33. 3、GDB基本命令列表

  34. 关于watch 变量 • 注意,watch设置的观察点当值有改变时才会有输出。 • 有时对断点的变量设置了观察点,但是c(continue),n(ext)使用的不适当会看不到变量值的变化效果。 • 某个求字符串反序的程序中的一段代码 for(i=0;i<size;i++) str2[size-i]=str1[i]; (a) str2[size+1]=‘\0’; (b) gdb调试时,在a处设置断点,run后停在a处,设置对变量的观察点watch str2[size-i]。然后按n一步步执行,看不到值的变化,按c才能看到效果。

  35. 4、GDB的help命令 (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 internals -- Maintenance commands … 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. • 直接输入help,可查看到GDB命令种类 • 查看某个类中的各种命令。如上步中列出的种类data • 查看某个命令 (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 "help" 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 printed and saved in the value history, if it is not void.

  36. 实验几个简单C程序。 • 课本及实验教材中陆续会出现各种C程序。均可作实验。 • 出现的函数很多是各种功能的linux系统调用,注意多积累对系统调用的认识。

  37. 下载源代码包,解压缩软件包的归档文件到一个目录下。下载源代码包,解压缩软件包的归档文件到一个目录下。 (利用tar命令) 配置源代码,使其本地化,包括设置安装路径、目标环境(指定编译器)、软件功能裁剪等。 (利用配置工具——源码所在目录下的configure可执行文件,设置里面的开关参数即可) 配置后会生成makefile文件,它记录了配置的细节和对应的软件编译流程。 编译。根据makefile文件编译后,源代码和可执行文件混合放在安装目录下。 (利用源代码工程管理工具——make) 安装。即将可执行文件和相应的库文件拷贝到目标目录下,并建立相对应的链接文件。 (利用make install命令) 建立工作目录 mkdir ~/mygcc cd ~/mygcc 在mygcc目录下解压源代码包 tar –vxjf /tmp/gcc-4.4.0.tar.bz2 (或tar –vxzf /tmp/gcc-4.4.0.tar.gz) 准备一个放编译结果的目录 mkdir gccbuild cd gccbuild gccbuild下配置安装的目标路径 ~/mygcc/gcc-4.4.0/configure –prefix=/usr/local/gcc-4.4.0 编译make 安装make install /usr/local/gcc-4.4.0/bin目录下会出现gcc的可执行文件 在bin目录下测试执行 ./gcc ./gcc –v 建立新版本gcc的链接文件以防与旧版冲突 ln –s /usr/local/gcc-4.4.0/bin/gcc gcc4 测试一个c语言程序 cd任意目录 写一个简单的c程序, gcc4 test.c –o test 源代码安装GCC(选看)

More Related