《C语言-GCC基础培训.ppt》由会员分享,可在线阅读,更多相关《C语言-GCC基础培训.ppt(77页珍藏版)》请在三一办公上搜索。
1、1,C语言-GCC,上海*通信技术有限公司 Jim()2011-05,2,培训大纲,一、gcc简介二、gcc编译过程三、gcc编译选项四、静态/动态链接库五、其它,3,gcc简介,名称:GNU project C and C+Compiler GNU Compiler Collection gcc是一个全功能的ANSIC兼容编译器,它是所有UNIX系统可用的C编译器。gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%30%。,4,查看版本信息,5,查看安装路径,6,相关文件类型,c 为后缀的文件,C语言源代码文件;.a 为后缀的文件,是由目
2、标文件构成的档案库文件;.C,.cc或.cxx 为后缀的文件,是C+源代码文件;.h 为后缀的文件,是程序所包含的头文件;.i 为后缀的文件,是已经预处理过的C源代码文件;.ii 为后缀的文件,是已经预处理过的C+源代码文件;.m 为后缀的文件,是Objective-C源代码文件;.o 为后缀的文件,是编译后的目标文件;.s 为后缀的文件,是汇编语言源代码文件;.S 为后缀的文件,是经过预编译的汇编语言源代码文件。,7,gcc编译的4个过程,预处理(也称预编译,Preprocessing):命令gcc首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(include)、预编译语
3、句(如宏定义define等)进行分析。编译(Compilation):接着调用cc1进行编译,这个阶段根据输入文件生成以.o为后缀的目标文件。汇编(Assembly):汇编过程是针对汇编语言的步骤,调用as进行工作。连接(Linking):当所有的目标文件都生成之后,gcc就调用 ld来完成最后的关键性工作,这个阶段就是连接,8,可执行程序的生成过程,预处理(Preprocessing):分析各种预处理命令,如#define,#include,#if等;编译(Compilation):根据输入文件产生汇编语言的程序;汇编(Assembly):将汇编语言输入,产生扩展名为.o的目标文件;链接(L
4、inking):以.o目标文件,库文件作为输入,生成可执行文件;,源程序文件(.h,.c),经预处理的文件(.i),汇编语言文件(.s),目标文件(.o),可执行程序(.out),9,培训大纲,一、gcc简介二、gcc编译过程三、gcc编译选项四、静态/动态链接库五、其它,10,GCC编译过程,典型的编译过程 test.c 预处理 test.i 编译 test.s 汇编test.o 连接 test$cat test.c(查看程序源代码)#include int main(int argc,char*argv)printf(hello worldn);return 0;$gcc o test t
5、est.c(编译连接程序)$./test(执行test程序),11,1、没有任何选项:gcc helloworld.c 结果会在和helloworld.c相同的目录下产生一个a.out的可执行文档。2、-o选项,指定输出文档名:gcc-o helloworld helloworld.c-o意思是Output即需要指定输出的可执行文档的名称。这里的名称为helloworld。3、-c选项,只编译汇编,不连接:gcc-c helloworld.c-c意思就是Compile,产生一个叫helloworld.o的目标文档 4、-S选项,产生汇编源文档:gcc-S helloworld.c-S意思就是a
6、Ssemble,产生一个叫helloworld.s的汇编源文档 5、-E选项,预处理C源文档:gcc-E helloworld.c-E意思就是prEprocess。输出不是送到一个文档而是标准输出。当然能够对他进行重定向:gcc-E helloworld.c helloworld.txt,12,预处理,预编译命令:$gcc-o test.i-E test.c或者$cpp-o test.i test.c 这里cpp不是值c plus plus,而是the C Preprocessor执行结果:生成预处理后的文件test.i,该文件包含了test.c需要的所有的类型和函数申明。原理:读取c源程序,
7、对伪指令和特殊符号进行处理。包括宏,条件编译,包含的头文件,以及一些特殊符号。基本上是一个替换的过程。,13,#define用法,#include#define AA 100int main(void)AA BBprintf(“hellon”);预处理命令gcc E hello.c DBB=hellogcc E hello.c DBB=“printf(”hello”);”gcc E hello.c DBB(等效于-DBB=1),注释这一行看看预处理的结果,-D表示在命令行中传入宏定义-DBB=后面是一个宏的定义,可以加双引号。,14,#define带参数,#include#define AA(
8、a,b)a=bint main(void)AA(int a,1);printf(“hellon”);预处理命令gcc E hello.c,展开就成了:int a=1;AA宏带两个参数,15,#define带参数,#include#ifdef AAaa#elif defined BBbb#elif defined CCcc#elseother#endifint main(void)printf(“hellon”);gcc E hello.c DAA=1aaint main(void)printf(“hellon”);,#ifdef AA 等效于#if defined AA表示当定义了宏AA,表示
9、除此之外的情况,表示否则定义了宏CC的情况,16,#define带参数,#include#if AAaa#elif BBbb#elif CCcc#elseother#endifint main(void)printf(“hellon”);,#if AA 表示AA非零的情况也就是AA除了0其它数字都为真,表示除此之外的情况,#elif BB 表示BB非零的情况#elif表示否则如果,17,gcc E hello.c DAA=1,aaint main(void)printf(“hellon”);gcc E hello.c DAA=0otherint main(void)printf(“hellon
10、”);,18,#的用法,在函数式宏定义中,#运算符用于创建字符串,#运算符后面应该跟一个形参(中间可以有空格或Tab),例如:#define STR(s)#schar*p=STR(helloworld)结果变成:char*p=“helloworld”,19,#的用法,在宏定义中可以用#运算符把前后两个预处理Token连接成一个预处理Token,和#运算符不同,#运算符不仅限于函数式宏定义,变量式宏定义也可以用。例如:#define FOO(a)foo#aint a=FOO(bar);int b=FOO();预处理之后变成:int a=foobar;int b=foo;,20,预处理头文件xxx
11、.h,#ifndef HEADER_FILENAME#define HEADER_FILENAME/*body of header*/#endif当xxx.h被多次包含的时候。,21,有三个头文件和一个C文件,common.h file2.h file3.h main.c#ifndef _COMMON_H_#define _COMMON_H_static int test(void)printf(“hellon”);#endiffile1.h文件内容如下:#include“common.h”file2.h文件内容如下:#include“common.h”main.c内容如下#include#i
12、nclude“file1.h”#include“file2.h”int main(void)test();gcc o main main.c,如果没有写上红色部分的,是什么情况。,22,常用的#debug宏定义,int main()printf(“here%s%s%dn”,_FILE_,_func_,_LINE_);printf(“here%s%s%dn”,_FILE_,_func_,_LINE_);printf(“here%s%s%dn”,_FILE_,_func_,_LINE_);,太多printf不好区分如何打出printf的时候也打出行号,函数,文件之类的信息,23,编译,编译命令:$
13、gcc-o test.s-S test.i(-S编译选项)$cc1-o test.s test.i(cc1为C语言真正编译器)结果:生成汇编文件test.s,test.s中包含了AT&T的x86汇编代码。作用:通过词法和语法分析,确认所有指令符合语法规则(否则报编译错),之后翻译成对应的中间码,在linux中被称为RTL(Register Transfer Language),通常是平台无关的,这个过程也被称为编译前端。编译后端对RTL树进行裁减,优化,得到在目标机上可执行的汇编代码。gcc采用as作为其汇编器,所以汇编码是AT&T格式的,而不是Intel格式,所以在用gcc编译嵌入式汇编时,
14、也要采用AT&T格式。,24,汇编,汇编命令:$gcc-o test.o-c test.s$as-o test.o test.s执行结果:生成目标机器指令文件test.o(可以通过objdump查看汇编指令)原理:把汇编语言代码翻译成目标机器指令,用file test.o 可以看到test.o是一个relocatable的ELF文件,通常包含.text.rodata代码段和数据段。可用readelf-r test.o查看需要relocation的部分。,25,链接,执行命令:$gcc-o test test.o执行结果:生成可执行文件test(可用objdump查看)原理:将在一个文件中引用的
15、符号同在另外一个文件中该符号的定义链接起来,使得所有的这些目标文件链接成为一个能被操作系统加载到内存的执行体。(如果有链接不到的符号定义,或者重复定义等,会报链接错)。用file test 可以看到test是一个executable的ELF文件。,26,培训大纲,一、gcc简介二、gcc编译过程三、gcc编译选项四、静态/动态链接库五、其它,27,gcc的使用,基本使用格式$gcc 选项 文件名例:,/text.c#includevoid main()printf(“Hello World!n”);,$gcc test.c$./a.outHello World!或$gcc-o test tes
16、t.c$./testHello World!,28,常用选项及含义,29,gcc的常用选项,30,gcc的常用选项,31,gcc的常用选项,32,示例,33,-Wall:允许所有有用的警告(建议总是使用该选项),/*bad.c*/#include int main(int argc,char*argv)printf(“Two plus two is%fn”,4);return 0;,例1:$gcc bad.c o bad例2:$gcc Wall bad.c o bad,33,例1:,34,-o:定义输出文件,例:编译多个源文件$gcc-Wall main.c hello.c-o hellowo
17、rld,/*hello.h*/void hello(const char*name);,/*hello.c*/#include#include hello.h void hello(const char*name)printf(Hello,%s!n,name);,/*main.c*/#include hello.h int main(int argc,char*argv)hello(world);return 0;,34,例2:,35,-l:链接外部库文件,库是已经编译好并能被链接入程序的对象文件的集合。库中提供一些最常用的系统函数,比如象C的数学库中求平方根函数sqrt。,库通常被存储在扩展
18、名为“.a”或“.so”的特殊归档文件中。,C标准库自身存放在“/usr/lib/libc.a”中,包含ANSI/ISO C标准指定的各个函数,是默认自动加载的库。,/*sqrt.c*/#include#include int main(int argc,char*argv)double r=sqrt(3.0);printf(The square root of 3.0 is%fn,r);return 0;,例:$gcc-Wall sqrt.c-o sqrt,ccbR6Ojm.o:In function main:ccbR6Ojm.o(.text+0 x19):undefined refere
19、nce to sqrt,35,例:,36,-l:链接外部库文件,函数sqrt()并不定义在源程序中或默认的C库“libc.a”中。,为了使得编译器能把sqrt()函数链接到主程序“sqrt.c”,需要提供“libm.a”库。,例:$gcc-Wall sqrt.c/usr/lib/libm.a-o sqrt,/usr/lib/libm.a,-lm,$gcc-Wall sqrt.c-lm-o sqrt,编译器选项“-lNAME”试图链接标准库目录下的文件名为“libNAME.a”中的对象文件,36,例:,37,函数库的链接次序,原则:包含函数定义的库应该出现在任何使用到该函数的源文件和对象文件之后
20、,例1:$gcc-Wall-lm sqrt.c-o sqrt(incorrect)$gcc-Wall sqrt.c-lm-o sqrt(correct),例2:$gcc-Wall sqrt.c-lglpk-lm-o sqrt,程序“sqrt.c”用到了GNU Linear Programming库“libglpk.a”,而该库又依次用到数学库“libm.a”,那么应当这么编译:,37,例:,38,-L:设置库文件的搜索路径,如果链接时用到的库不在gcc用到的标准库目录中,就会报这样的错。,/usr/local/lib/usr/lib/,例:$gcc-Wall-L/tmp/lib sqrt.c-
21、lm-o sqrt,-L/tmp/lib,38,例:,39,-I:设置头文件的搜索路径,如果头文件不在gcc用到的标准include文件路径中,就会报这样的错。,/usr/local/include/usr/include/,例:$gcc-Wall-I/tmp/include sqrt.c-lm-o sqrt,-I/tmp/include,39,例:,40,生成预处理文件,命令-E选项使得gcc生成预处理文件后停止。$gcc E hello.c o hello.i,预处理文件hello.i的部分内容.extern void funlockfile(FILE*_stream);#679/usr/
22、include/stdio.h 3#2 hello.c 2int main(void)printf(hello gcc!n);return 0;,41,生成汇编文件,命令$gcc S hello.c o hello.s,汇编文件hello.s的部分内容.main:pushl%ebpmovl%esp,%ebp.addl$16,%espmovl$0,%eaxleaveret.,42,生成二进制文件,生成目标文件命令:$gcc c hello.c o hello.o生成可执行文件命令:$gcc hello.c o hello运行程序$./hellohello gcc!,43,培训大纲,一、gcc简介
23、二、gcc编译过程三、gcc编译选项四、静态/动态链接库五、其它,44,静态库与动态库,创建函数库分类:静态库:在编译过程中将库函数代码直接加入到生成的可执行程序中,程序运行过程中不需要利用库函数。共享库:编译时,只是在生成的可执行程序中简单指定需要使用的库函数信息,程序运行过程中需要利用库函数。动态库:共享库的一种变化形式,目前大都采用共享库的方式。命名:静态库:前缀lib+库名+.a(libm.a,libstdc+.a等)共享库:前缀lib+库名+.so+.版本号(libm.so.6,libc.so.6),45,创建静态库,静态函数库是一组目标文件(*.o)的集合创建步骤:gcc-c te
24、st1.c test2.c(生成test1.o,test2.o)ar-cr libtest.a test1.o test2.o(生成函数库libtest.a)ar函数说明:用途:创建和修改库函数,或从库函数提取目标文件举例:ar-rs lib-name list-of-files(将列表中的目标文件加入到库中,并产生索引文件)ar-ds lib-name list-of-files(将列表中列出的目标文件从库中删除,并产生索引文件)ar-x lib-name list-of-files(不修改库文件,从库中提取列表中列出的目标文件),46,创建静态库示例源码,创建静态库的方法:ar,cacul
25、ation.c#include int main(void)int x=5;int y=3;printf(x+y=%3dn,add(x,y);printf(x-y=%3dn,minus(x,y);printf(x*y=%3dn,multiply(x,y);printf(x%y=%3dn,mod(x,y);return 1;,add_minus.cint add(int x,int y)int result;result=x+y;return result;int minus(int x,int y)int result;result=x-y;return result;,multiply_mo
26、d.cint multiply(int x,int y)int result;result=x*y;return result;int mod(int x,int y)int result;result=x%y;return result;,47,创建静态库示例操作命令,48,一个容易忽略的顺序问题,静态库不能先于原程序链接,这是因为开始时还没有任何未定义的符号,库中的内容不会被链入,所以应该注意将静态库的使用(-l选项)都写在最后。,49,创建、使用共享库示例,vicknec$gcc-fPIC-c add_minus.c vicknec$gcc-fpic-c multiply_mod.c v
27、icknec$gcc-shared-fpic-o libalg.so add_minus.o multiply_mod.o vicknec$gcc-o cacul-lalg caculation.c/usr/bin/ld:cannot find-lalg collect2:ld returned 1 exit status vicknec$gcc-o cacul-L.-lalg caculation.c vicknec$./cacul./cacul:error while loading shared libraries:libalg.so:cannot open shared object
28、file:No such file or directory,50,创建共享库步骤,创建共享库 gcc-c-fPIC test1.cgcc-c-fPIC test2.cgcc-shared-fPIC-o libtest.so test1.o test2.o编译使用了共享库的程序gcc-o main Ldir-ltest main.c,51,共享库系统自动动态加载问题,1.拷贝动态库文件到/lib或/usr/lib去$cp libalg.so/usr/lib or$cp libalg.so/lib2.改变环境变量LD_LIBRARY_PATH$LD_LIBRARY_PATH=$PWD$expor
29、t LD_LIBRARY_PATH,52,应用程序自身完成动态加载,可以在自己的程序中使用 dlopen()。该函数将打开一个新库,并把它装入内存。dlopen()在 dlfcn.h 中定义,并在 dl 库中实现。,53,应用程序自身完成动态加载示例,#include#include int main(void)int x=5;int y=3;void*handle;int(*dl_add)(int,int);int(*dl_mod)(int,int);,handle=dlopen(/usr/lib/libalg.so,RTLD_LAZY);dl_add=dlsym(handle,add);d
30、l_mod=dlsym(handle,mod);printf(x+y=%3dn,dl_add(x,y);printf(x%y=%3dn,dl_mod(x,y);dlclose(handle);return 1;,54,检查库依赖关系,函数库之间的相互引用ldd的使用:用于查看库函数之间的依赖性vicknec gcc-lab$cd/usr/libvicknec lib$ldd libtiff.so libjpeg.so.62=/usr/lib/libjpeg.so.62(0 x4004c000)libz.so.1=/usr/lib/libz.so.1(0 x4006b000)libc.so.6=
31、/lib/i686/libc.so.6(0 x40079000)/lib/ld-linux.so.2=/lib/ld-linux.so.2(0 x80000000),55,动态库路径搜索的先后顺序,编译目标代码时指定的动态库搜索路径;环境变量LD_LIBRARY_PATH指定的动态库搜索路径;配置文件/etc/ld.so.conf中指定的动态库搜索路径;默认的动态库搜索路径/lib;默认的动态库搜索路径/usr/lib.,56,总结:动态共享库的好处,1.动态共享库是共享的,节省了物理开销。2.库版本更新容易,运行时调用,库更新后不用重新链接。3.允许用户在运行时再确定调用哪个库。使得在程序中
32、添加或者删除一个模块时,都不需要在编译时指定库。注意,如果动态共享库无法加载,可能是路径的问题,或是依赖的问题。,57,培训大纲,一、gcc简介二、gcc编译过程三、gcc编译选项四、静态/动态链接库五、其它,58,GNU C 扩展简介,gcc使用long long数据类型提供64位存储单元。内联函数:要求内联函数足够短小,使得能够在代码中展开,同时编译器检查函数类型。要使用-O选项。-finline-functions.使用attribute关键字指明代码相关信息方便优化。gcc对case做了扩展。case语句可以对应一个范围,在case关键字后列出范围的两个边界值,用“空格省略号空格”分隔
33、。,59,多个文件的C程序,为了方便代码重用,通常将主函数和其他函数放在不同文件中的方法。每个函数都有函数声明(函数头)和函数实现(函数体)两部分组成。函数头一般放在头文件中(*.h)中,而函数的定义文件放在实现文件(*.c、*.cpp)中,60,编译多个文件,61,假设3个文件保存在同一个目录下面,如果还使用:命令:$gcc my_app.c o my_app会编译通过吗?,62,编译多个文件,目录结构(1)编译命令$gcc my_app.c greeting.c o my_app目录结构(2)编译方式(1)$gcc my_app.c functions/greeting.c o my_ap
34、p-I functions,63,编译多个文件,目录结构(2)编译方式(2)分步编译命令:1、$gcc-c my_app.c-I functions 2、$gcc-c functions/greeting.c3、$gcc my_app.o greeting.o o my_app思路:编译每一个.c文件,得到.o的目标文件;将每一个.o的目标文件链接成一个可执行的文件;,64,ar option,option cCreate a fileoption dDelete a file from the archiveoption pPrint a list of files in the archi
35、veoption qAppend files to the archiveoption rInsert new files in the archive by replacing if a file already exists in the archiveoption tDisplaying contents of an archiveoption xExtracting files from an archive,65,ranlib Utility,The“ranlib”command is used to create index entries inside an archive fi
36、le.示例:$ranlib static-lib-name等价于$ar s static-lib-name,66,nm Utility,used to list symbols used in an object file.示例:$nm-s libcommon.a$nm-s a.out 另外:a option with the nm command also shows the debug symbols.,67,objdump Utility,-fDisplaying Header Information-h Displaying Section Headers-dDisassembling
37、 a File-aDisplaying Information about Library Files,68,size Utility,The size utility displays sizes of each section in an object file.示例:rootboota#size a.out text data bss dec hex filename 1015 232 24 1271 4f7 a.out,69,ldd Utility,The ldd utility is very useful in finding out the dependencies of an
38、executable on shared libraries.示例:rootboota#ldd a.out libc.so.6=/lib/i686/libc.so.6(0 x4002c000)/lib/ld-linux.so.2=/lib/ld-linux.so.2(0 x40000000)rootboota#,70,建立自己的GCC 编译环境,一个系统上如何同时存在并使用多个版本的GCC编译器?建立目标目录:在gcc源代码同一级目录下(与源目录$srcdir是同级目录)%mkdir gcc-build%cd gcc-build配置环境:%./gcc-3.4.0/configure-prefi
39、x=/usr/local/gcc-3.4.0-enable-threads=posix-disable-checking-enable-long-long-host=i386-redhat-linux-with-system-zlib-enable-languages=c,c+,java将GCC安装在目录下,支持C/C+和JAVA语言,71,编译安装:%make&make install其它配置:GCC 3.4.0的所有文件,包括命令文件(如gcc、g+)、库文件等都在$destdir目录下分别存放,如命令文件放在bin目录下、库文件在lib下、头文件在include下等。由于命令文件和库文件
40、所在的目录还没有包含在相应的搜索路径内,所以必须要作适当的设置之后编译器才能顺利地找到并使用它们。用符号连接的方式实现,这样做的好处是我仍然可以使用系统上原来的旧版本的GCC编译器。%ln-s$destdir/bin/gcc gcc34库路径的设置:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:destdir/libsetenv LD_LIBRARY_PATH/usr/local/gcc-3.4.0/lib:$LD_LIBRARY_PATH,72,GCC的编译环境,工具:gcc c编译器,它在链接时使用c库 cc1 实际的c编译器 cc1plus 实际的c+编
41、译器 collect2 使用collect2产生特定的全局初始化代码,后台处理是传递参数给ld完成实际的链接工作。crt0.o 初始化和结束代码 libgcc 平台相关的库,73,binutils相关工具:as:gnu汇编工具 gprof:性能分析工具 ld:gnu链接器,链接器可以读写各种目标文件中的信息,通过BFD(binary file descriptor)提供的工具实现,BFD定义了类似a.out,elf,coff等目标文件的格式 make:objcopy:目标文件从二进制格式翻译或复制到另一种 objdump:显示目标文件的各种信息 strings:显示文件的字符串 strip:去
42、除符合表 readelf:分析elf并显示信息,74,gcc预定义宏 _BASE_FILE_ 完整的源文件名路径 _cplusplus 测试c+程序 _DATE_ 日期 _FILE_ 源文件名 _func_ 替代_FUNCTION_,_FUNCTION_以被GNU不推荐使用 _TIME_ 日期 _LINE_ 行数 _VERSION_ gcc版本,75,常用优化选项gcc默认提供了5级优化选项的集合:-O0:无优化(默认)-O和-O1:使用能减少目标文件大小以及执行时间并且不会使编译时间明显增加的优化.在编译大型程序的时候会显著增加编译时内存的使用.-O2:包含-O1的优化并增加了不需要在目标文
43、件大小和执行速度上进行折衷的优化.编译器不执行循环展开以及函数内联.此选项将增加编译时间和目标文件的执行性能.-Os:专门优化目标文件大小,执行所有的不增加目标文件大小的-O2优化选项.并且执行专门减小目标文件大小的优化选项.-O3:打开所有-O2的优化选项并且增加-finline-functions,-funswitch-loops,-fpredictive-commoning,-fgcse-after-reload and-ftree-vectorize优化选项.,76,GCC 的编译错误类型C语法错误 错误资讯文件source.c中第n行有语法错误(syntex errror)头文件错误 错误资讯找不到头文件head.h(Can not find include file head.h)档案库错误 错误资讯连接程序找不到所需的函数库未定义符号 错误资讯有未定义的符号(Undefined symbol)。,77,推荐读物,GCC 中文手册学习使用GCCUsing the GNU Compiler Collection,
链接地址:https://www.31ppt.com/p-6503689.html