1 . 什么是预处理
编译分为4个步骤:
① .c文件生成.i文件,预处理;
② .i文件生成.s文件,编译;
③ .s文件生成.o文件,汇编;
④ .o文件生成可执行文件,链接;
文件中:$可以直接到文件底部;
gcc -o main.i main.c -E
生成预处理文件,-E表示只进行预处理;、
查看预处理文件只需 vi main.i
预处理做的第一件事:展开头文件,在.i文件中可以显示,不再以include的形式出现;然后再进行宏替换。
2 . 预处理之宏定义
#define R 10
预处理的第二步宏替换就是把比如 int a = R;
这样的语句替换成int a = 10;
不要认为这个10是int,而认为这个10是个字符串,替换过程中单纯的将字符串替换而已;
宏的本质:发生在预处理阶段的字符串替换;
例:
#include<stdio.h>
#define R 10
#define M int main()
M
{
int a=R;
printf("a=%d\n",a);
printf("hello world!\n");
return 0;
}
程序也可以运行出来。
在预处理阶段,宏不考虑编译器的语法;
3 . 预处理之宏函数
#include<stdio.h>
#define R 20
#define M int main()
#define N(n) n*10
M
{
int a=R;
printf("a=%d\n",a);
int b=N(a);
printf("b=%d\n",b);
return 0;
}
运行结果:
linux@ubuntu:~/workspace2/les1$ ./a.out
a=20
b=200
.i文件中int b=N(a);
被替换成了int b=a*10;
#define ADD(a,b) a+b
int main()
{
int a=20;
int b=200;
int d=ADD(a,b);
int e=ADD(a,b) * ADD(a,b);
}
d的结果可以实现ADD函数的功能;
e的理想结果是48400,但实际结果是4220;
原因:.i文件中宏替换的结果是 int e= a+b*a+b;
·运算是编译之后执行的时候才会进行,在预处理阶段不会进行运算操作。
需要把.c文件改成 int e= (ADD(a,b))*(ADD(a,b));
(yy是复制,p是粘贴,u是撤销,ctrl+r取消撤销);
宏函数跟正常的函数有什么区别?
宏函数没有返回类型和参数类型,可以不考虑类型;
在预处理阶段,除了宏之外,还提供了条件编译的功能,可以按照不同的条件去编译不同的程序部分,从而产生不同的代码文件,对程序的移植和调试很有用。
4 . typedef
typedef是一个关键字,可以给变量类型起个别名;
typedef int tni;
typedef int* p;
p q=NULL;// 写法等同于int *q = NULL;
给int*类型起个别名叫p;
typedef与宏的区别:
1.typedef的结果以分号结尾;
2.typedef在预处理是不进行替换,.i文件中不被替换;
3.宏定义了之后下面都可以使用,而typedef有作用域,一般在本函数体内?
typedef通常给自己自定义的数据类型起个别名:
typedef unsigned long size_t;
结构体未使用typedef:
struct stu{
};
struct stu a;
结构体使用typedef:
typedef struct stu{
}stu_t;
stu_t a;