gcc所支持后缀名
.c C原始程序
.C/.cc/.cxx C++原始程序
.m Objective-C原始程序
.i 已经过预处理的C原始程序
.ii 已经过预处理的C++原始程序
.s/.S 汇编语言原始程序
.h 预处理文件(头文件)
.o 目标文件
.a/.so 编译后的库文件
GCC的基本用法和选项
Gcc最基本的用法是∶gcc [options] [filenames]
-c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。
-o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
-g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。
-O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,
但是,编译、连接的速度就相应地要慢一些。
-O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。
-I dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。
-L dirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数。
生成预处理代码
$ gcc –E test.c -o test.i
用wc命令,查看这两个阶段代码大小:
$ wc test.c test.cpp
9 16 127 test.c
842 1934 16498 test.cpp
851 1950 16625 总用量
test.i比test.c增加了很多内容,主要是放在系统提供的include文件中的
生成汇编代码
检查语法错误,并生成汇编文件
$ gcc –S test.c –o test.s
生成目标代码
方法一,用gcc直接从C源代码中生成目标代码:
$ gcc –c test.s –o test.o
方法二,用汇编器从汇编代码生成目标代码:
$ as test.s –o test.o
生成可执行程序
将目标程序链接库资源,生成可执行程序
$ gcc test.s –o test
条件编译
一、根据宏是否定义,其语法如下:
#ifdef <macro>
……
#else
……
#endif
二、根据宏的值,其语法如下:
#if <macro>
……
#else
……
#endif
结构体
Example:
定义一个职工worker结构体如下:
struct worker
{
long number;
char name[20];
char sex;
int age; // age是成员名
float salary;
char address[80];
}; //注意分号不能省略
int age = 10; //age是变量名
在定义类型的同时定义变量
这种形式的定义的一般形式为:
struct 结构体名
{
成员列表;
}变量名;
结构体大小
sizeof(运算量)
结构体变量的初始化
struct 结构体名 变量名={初始数据表};
另一种是在定义结构体类型时进行结构体变量的初始化。
struct 结构体名
{
成员列表;
}变量名={初始数据表};
结构体数组
1. 先定义结构体类型,再用它定义结构体数组。
结构体数组的定义形式如下:
struct 结构体名
{
成员表列;
};
struct 结构体名
例如:
struct student
{
char name[20];
char sex;
int age;
char addr[20];
};
struct student stu[3];
共用体
例如:
union gy
{
int i;
char c;
float f;
};
就里定义了一个共用体类型union gy,它由三个成员组成,这三个成员在内存中使用共同的存储空间。由于共用体中各成员的数据长度往往不同,所以共用体变量在存储时总是按其成员中数据长度最大的成员占用内存空间。
在这一点上共用体与结构体不同,结构体类型变量在存储时总是按各成员的数据长度之和占用内存空间。
例如,定义了一个结构体类型:
struct gy
{
int i;
char c;
float f;
};
则结构体类型struct gy的变量占用的内存大小为2+1+4=7个字节(不考虑字节对齐) 。
在程序中经常使用结构体与共用体相互嵌套的形式。
即共用体类型的成员可以是结构体类型,或者结构体类型的成员是共用体类型。
例如,下列结构体类型datas的第三个成员是共用体类型:
struct datas
{
char *ps;
int type;
union
{
float fdata;
int idata;
char cdata;
}udata;
};
typedef
在C语言中,允许使用关键字typedef定义新的数据类型
其语法如下:
typedef <已有数据类型> <新数据类型>;
如:
typedef int INTEGER;
这里新定义了数据类型INTEGER, 其等价于int
INTEGER i; <==> int i;
在C语言中经常在定义结构体类型时使用typedef,例如
typedef struct _node_
{
int data;
struct _node_ *next;
} listnode, *linklist;
这里定义了两个新的数据类型listnode和linklist。
其中listnode 等价于数据类型struct _node_ 而 linklist等价于struct _node_ *
内存管理
C/C++定义了4个内存区间:
代码区/全局变量与静态变量区/局部变量区即栈区/动态存储区,即堆区。
静态存储分配
通常定义变量,编译器在编译时都可以根据该变量的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。
在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
动态存储分配
有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为。
所有动态存储分配都在堆区中进行。
从堆上分配,亦称动态内存分配。程序在运行的时候用malloc申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
堆内存的分配与释放
当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。
堆区是不会自动在分配时做初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化。
malloc/free
void * malloc(size_t num)
void free(void *p)
malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
malloc申请到的是一块连续的内存,有时可能会比所申请的空间大。其有时会申请不到内存,返回NULL。
malloc返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void * 转换成所需要的指针类型。
如果free的参数是NULL的话,没有任何效果。
释放一块内存中的一部分是不被允许的。
malloc/free 注意事项:
动态分配的变量或对象的生命期。无名对象的生命期并不依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用。我们也称堆空间为自由空间(free store)就是这个原因。但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放是一件很容易失控的事,往往会出错。
malloc/free 野指针:
不是NULL指针,是指向“垃圾”内存的指针。“野指针”是很危险的。 “野指针”的成因主要有两种:
指针变量没有被初始化。
指针p被free之后,没有置为NULL,让人误以为p是个合法的指针。
指针操作超越了变量的作用范围。这种情况让人防不胜防。