GCC简介:
GCC编译器的版本:
gcc所支持后缀名解释:
Gcc最基本的用法是∶gcc [options] [filenames]
第一类∶C语法错误
错误信息∶文件source.c中第n行有语法错误(syntex errror)。有些情况下,一个很简单的语法错误,gcc会给出一大堆错误,我们最主要的是要保持清醒的头脑,不要被其吓倒,必要的时候再参考一下C语言的基本教材。
第二类∶头文件错误
错误信息∶找不到头文件head.h(Can not find include file head.h)。这类错误是源代码文件中的包含头文件有问题,可能的原因有头文件名错误、指定的头文件所在目录名错误等,也可能是错误地使用了双引号和尖括号。
第三类∶档案库错误
错误信息∶链接程序找不到所需的函数库(ld: -lm: No such file or directory )。这类错误是与目标文件相连接的函数库有错误,可能的原因是函数库名错误、指定的函数库所在目录名称错误等,检查的方法是使用find命令在可能的目录中寻找相应的函数库名,确定档案库及目录的名称并修改程序中及编译选项中的名称。
第四类∶未定义符号
错误信息∶有未定义的符号(Undefined symbol)。这类错误是在连接过程中出现的,可能有两种原因∶一是使用者自己定义的函数或者全局变量所在源代码文件,没有被编译、连接,或者干脆还没有定义,这需要使用者根据实际情况修改源程序,给出全局变量或者函数的定义体;二是未定义的符号是一个标准的库函数,在源程序中使用了该库函数,而连接过程中还没有给定相应的函数库的名称,或者是该档案库的目录名称有问题,这时需要使用档案库维护命令ar检查我们需要的库函数到底位于哪一个函数库中,确定之后,修改gcc连接选项中的-l和-L项。
GCC的编译流程分为四个步骤:
$ gcc –E test.c -o test.i
用wc
命令,查看这两个阶段代码大小:$ wc test.c test.i
9 16 127 test.c
842 1934 16498 test.i
851 1950 16625 总用量
test.i比test.c增加了很多内容,主要是放在系统提供的include文件中的。
检查语法错误,并生成汇编文件
$ gcc –S test.c –o test.s
$ gcc –c test.s –o test.o
$ as test.s –o test.o
将目标程序链接库资源,生成可执行程序$ gcc test.s –o test
、再运行./test
。
-g
’# gcc -g test.c -o test
# gdb test
命令 | 按键 |
---|---|
查看断点情况 | (gdb) info b |
单步运行 | (gdb) n/(gdb) s |
查看文件 | (gdb) l |
设置断点 | (gdb) b 6 |
查看变量值 | (gdb) p n |
运行代码 | (gdb) r |
恢复程序运行 | (gdb) c |
帮助 | (gdb) help [command] |
退出 | (gdb) q |
编译器根据条件的真假决定是否编译相关的代码。
其语法如下:
#ifdef
……
#else
……
#endif
定义:
还有一种方式就是直接放数值0、1。
C/C++定义了4个内存区间:
有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为。
所有动态存储分配都在堆区中进行。
从堆上分配,亦称动态内存分配。程序在运行的时候用malloc申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。
堆区是不会自动在分配时做初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化。
void * malloc(size_t num)
:分配空间
void free(void *p)
:释放空间
注意事项:
free(p);
),实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针。不是NULL指针,是指向“垃圾”内存的指针。“野指针”是很危险的。 “野指针”的成因主要有两种:
工程管理器,顾名思义,是指管理较多的文件。
Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件的内容来执行大量的编译工作。
Make将只编译改动的代码文件,而不用完全编译。
Makefile是Make读入的唯一配置文件。
注意:命令行前面必须是一个“TAB键”,否则编译错误为:*** missing separator. Stop。
Makefile格式:
target : dependency_files
<TAB> command
例子:
f1.c:
f2.c:
head.h:
main.c:
通过makefile生成一个目标代码文件:(.c->.o->obj)。
如果有一个文件和clean重命名,报make:'test' is up to date.
的话,我们可以加一行语句,生成一个假目标,就可以继续执行了:
创建变量的目的:用来代替一个文本字符串:
递归展开方式VAR=var
它可以向后引用变量,但不能对该变量进行任何扩展,例如CFLAGS = $(CFLAGS) -O
简单方式VAR:=var
用这种方式定义的变量,会在变量的定义点,按照被引用的变量的当前值进行展开,这种定义变量的方式更适合在大的编程项目中使用,因为它更像我们一般的编程语言。
变量的使用:$(VAR)
。如果想用"$
“字符的话必须要用”$$
"。变量名一般大写。
dir := /foo/bar
FOO ?= bar
含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
可以通过+=
为已定义的变量添加新的值
Main=hello.o hello-1.o
Main+=hello-2.o
变量名 | 作用 |
---|---|
AR | 库文件维护程序的名称,默认值为ar。AS汇编程序的名称,默认值为as。 |
CC | C编译器的名称,默认值为cc。CPP C预编译器的名称,默认值为$(CC) –E。 |
CXX | C++编译器的名称,默认值为g++。 |
FC | FORTRAN编译器的名称,默认值为f77 |
RM | 文件删除程序的名称,默认值为rm -f |
ARFLAGS | 库文件维护程序的选项,无默认值。 |
ASFLAGS | 汇编程序的选项,无默认值。 |
CFLAGS | C编译器的选项,无默认值。 |
CPPFLAGS | C预编译的选项,无默认值。 |
CXXFLAGS | C++编译器的选项,无默认值。 |
FFLAGS | FORTRAN编译器的选项,无默认值。 |
变量名 | 作用 |
---|---|
$* | 不包含扩展名的目标文件名称 |
$+ | 所有的依赖文件,以空格分开,并以出现的先后为序,可能 包含重复的依赖文件 |
$< | 第一个依赖文件的名称 |
$? | 所有时间戳比目标文件晚的的依赖文件,并以空格分开 |
$@ | 目标文件的完整名称 |
$^ | 所有不重复的目标依赖文件,以空格分开 |
$% | 如果目标是归档成员,则该变量表示目标的归档成员名称 |
直接运行make。
选项
-C dir
读入指定目录下的Makefile-f file
读入当前目录下的file文件作为Makefile-i
忽略所有的命令执行错误-I dir
指定被包含的Makefile所在目录-n
只打印要执行的命令,但不执行这些命令-p
显示make变量数据库和隐含规则-s
在执行命令时不显示命令-w
如果make在执行过程中改变目录,打印当前目录名x : x.o y.o z.o
并且“x.c”、“y.c”和“z.c”都存在时,隐含规则将执行如下命令:
cc -c x.c -o x.o
cc -c y.c -o y.o
cc -c z.c -o z.o
cc x.o y.o z.o -o x
如果没有一个源文件(如上例中的x.c)和你的目标名字(如上例中的x)相关联,那么,你最好写出自己的生成规则,不然,隐含规则会报错的。
比如:下面的test就会报错,而要用f1
或者f2
、main
。
.c会自动生成.o,把三个.o生成target。
VPATH : 虚路径
在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。
Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src:../headers
上面的的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)
没用vpath:
用vpath:
下面是一个例子:
当前路径下的makefile文件:
当前目录下的所有文件和嵌套文件:
f1、f2、main下面的makefile文件内容:与下面类似。
这个执行过程就是当前下的makefile会把变量值export
传给各个嵌套文件夹下的makefile文件。就可以实现嵌套了。
执行结果: