test.c(源文件) --> 编译器 --> test.obj(目标文件,在debug里)
链接库和多个目标文件 经过 链接器的处理,最终生成可执行程序.exe
编译阶段
预处理/预编译阶段 :1.头文件的包含 2.define定义符号的替换,并删除定义的符号 3.删除注释 这三个都是文本操作
编译:把C语言代码转换成汇编代码
汇编:把汇编代码转换成二进制指令,形成符号表
链接阶段
合并段表
符号表的合并和重定位
预处理
__ FILE__进行编译源文件的位置
__ LINE__文件当前的行号
__ DATE__文件被编译的日期
__ TIME__文件被编译的时间
__ STDC__判断编译器是否服从标准C(ANSI C)数值就是1,否则就是没有定义这个内置符号
可以看出vs不遵循此标准
大多数oj网站使用gcc或者clang编译器
define定义标识符
后面加上“;”是一种非常坑爹的行为
#define MAX 1000
#define STR “hello world”
#define定义宏
对于宏不能递归
#define SQUARE(x) x*x
int main()
{
int r = SQUARE(5);
printf("%d ", r); //25
return 0;
}
为了避免以下情况发生
#define SQUARE(x) x*x
int main()
{
int r = SQUARE(5+1);
// r = 5 + 1*5 + 1
printf("%d ", r); //11
return 0;
}
可以define成
#define SQUARE(x) ((x)*(x))
#define PRINT(N,FORMAT) printf("the value of " #N " is "FORMAT"\n",N) //#会把参数对应的转换成字符串
int main()
{
int a = 10;
PRINT(a,"%d"); //the value of a is 10
double b = 3.14;
PRINT(b, "%lf"); //the value of b is 3.140000
return 0;
}
// ##可以把位于它两边的符号合成一个符号
#define CAT(Class,Num) Class##Num
int main()
{
int class106 = 100;
printf("%d", CAT(class, 106)); //100
return 0;
}
#define M 100
int main()
{
int a = M;
#undef M
return 0;
}
//offsetof宏模拟实现
struct s
{
char c1;
int i;
char c2;
};
#define OFFSETOF(type,m_name) (size_t)&(((type*)0)->m_name)
int main()
{
struct s s = { 0 };
printf("%d\n", offsetof(struct s, c1)); //0
printf("%d\n", offsetof(struct s, i)); //4
printf("%d\n", offsetof(struct s, c2)); //8
printf("%d\n", OFFSETOF(struct s, c1)); //0
printf("%d\n", OFFSETOF(struct s, i)); //4
printf("%d\n", OFFSETOF(struct s, c2)); //8
return 0;
}