首先,我们需要明确的是,由.c文件生成可执行文件的过程中都会经历哪些过程。
.c文件 --> .i文件 --> .s文件 --> .o文件 -->可执行文件
对应的操作依次为:预处理、编译、汇编、链接。
如gcc -o xx.i xx.c -E
为仅执行预处理的命令,预处理实际上是展开头文件和宏替换的过程。
宏定义
例:#define pi 3.14
如上文所述,发生在预处理阶段的宏替换是单纯的字符串的替换(并没有整型、浮点型等的概念)。
此外,还可以定义宏函数。例如#define ADD(a,b) a+b
,相对于一般的函数,它可以不考虑类型。
typedef(关键字)
typedef用于给变量类型起别名,在预处理之后并不会被替换,一般的用于给自定义的数据类型起别名。
结构体
结构体是不同类型变量的集合,相比较于数组(相同类型变量的集合)
- 声明和定义
struct student{
char name;
int age;
int class;};
- 初始化和访问
struct student = {"xiaoming",12,1};
int a = student.age;
此外,还可以定义结构体指针
struct student *s;
printf("name=%s\n",(*s).name)
//其中(*s).name等价于s->name
公用体(联合体)
关键字为union,几个变量共享同一个内存地址,且公用体变量和成员地址为同一地址。
- 声明和定义
union data {int a; char b; int c}
- 初始化(只能有一个常量)
union data data1;
data1.a=10;
内存占用情况
- 公用体:所占内存为成员中所占内存最长的成员的长度
- 结构体:公式:最后成员的偏移量+最后成员的大小+末尾的填充字节数
- 准则(结构体):每个成员相对于结构体首地址的偏移量必为当前成员所占内存大小的整数倍;若不是,编译器就会在成员之间添加填充字节;最后还需判断结构体成员的总大小是否为最宽成员的整数倍。
链表
下面记录一个动态链表的例程,仔细体会。
#include <stdio.h>
#include <malloc.h>
struct weapon{
int price;
int atk;
struct weapon * next;
};
struct weapon * create(){
struct weapon * head;
struct weapon * p1,*p2;
int n;
p1=p2=(struct weapon*)malloc(sizeof(struct weapon));
scanf("%d,%d",&p1->price,&p1->atk);
head = NULL;
while(p1->price!=0){
n++;
if(n==1)head=p1;
else p2->next=p1;
p2=p1;
p1=(struct weapon*)malloc(sizeof(struct weapon));
scanf("%d,%d",&p1->price,&p1->atk);
}
p2->next = NULL;
return (head);
}
int main(){
struct weapon *p;
p=create();
printf("%d,%d",p->price,p->atk);
return 0;
}