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); //25return 0;
}
为了避免以下情况发生
#define SQUARE(x) x*x
int main()
{int r = SQUARE(5+1);// r = 5 + 1*5 + 1 printf("%d ", r); //11return 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 10double b = 3.14;PRINT(b, "%lf"); //the value of b is 3.140000return 0;
}
// ##可以把位于它两边的符号合成一个符号#define CAT(Class,Num) Class##Num
int main()
{int class106 = 100;printf("%d", CAT(class, 106)); //100return 0;
}
#define M 100
int main()
{int a = M;
#undef Mreturn 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)); //0printf("%d\n", offsetof(struct s, i)); //4printf("%d\n", offsetof(struct s, c2)); //8printf("%d\n", OFFSETOF(struct s, c1)); //0printf("%d\n", OFFSETOF(struct s, i)); //4printf("%d\n", OFFSETOF(struct s, c2)); //8return 0;
}