在C语言编程中,代码的实现通过两种环境(翻译环境和执行环境)来实现
翻译环境分为:编译和链接
编译过程分为:预处理、编译和汇编
//预处理:头文件展开,条件编译,删除注释,宏替换
//编译:语法分析,将代码转换为汇编语言
//汇编:生成符号表,将汇编语言转换为二进制的机器指令
//连接:合并符号表,找到函数调用的地址连接起来
1.预处理(Preprocessing)
源文件.c和头文件.h被处理为以.i为后缀的文件
预处理阶段处理源文件中#开头的预编译指令,包括#include指令,用于包含头文件内容,以及宏定义等。
2.编译(Compiling)
编译器将预处理后的文件通过词法分析、语法分析、语义分析及优化,生成相应的汇编代码文件,即将高级语言代码转换成汇编语言代码
3.汇编(Assembling)
汇编器将汇编语言代码转换为机器可执行的二进制指令,生成目标文件(通常是以.o或.obj结尾)
4.链接
链接过程是把一堆文件链接在一起才生成可执行程序
链接过程主要包括:地址和空间分配、符号决议和重定位等步骤
5.预处理详解
5.1预定义符号
int main()
{
printf("%s\n", __FILE__);//进⾏编译的源⽂件
printf("%d\n", __LINE__);//⽂件当前的⾏号
printf("%s\n", __DATE__);//⽂件被编译的⽇期
printf("%s\n", __TIME__);//⽂件被编译的时间
}
输出结果如下图所示:
5.2#define
define定义常量
#define MAX 1000
define定义宏
#define ADD(x) x+x
int main()
{
int n = ADD(5);
printf("%d", n);//10
}
但是宏定义的使用需要多用括号,才能按照自己预想进行计算
且使用x++会有副作用
宏不能递归
5.3#和##运算符
#运算符所执⾏的操作可以理解为“字符串化”。
#define PRINT(n) printf("the value of "#n" is %d\n", n)
int main()
{
int a = 5;
PRINT(a);
int b = 10;
PRINT(b);
}
输出结果:
the value of a is 5
the value of b is 10
##运算符可以把位于它两边的符号合成⼀个符号
int int_max(int x, int y)
{
return x>y?x:y;
}
//使用##宏定义
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \
return (x>y?x:y); \
}
5.4#undef
用于移除一个宏定义
#undef NAME
//如果现存的⼀个名字需要被重新定义,那么它的旧名字⾸先要被移除
5.5条件编译
条件编译是一种在源代码中根据预定义的条件选择性地包含或排除代码的技术。在C语言中,条件编译通常通过预处理器指令来实现,其中最常用的指令是#ifdef(如果定义)、#ifndef(如果未定义)、#if(如果)和#else(否则)等。
#include <stdio.h>
#define __DEBUG__
int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i < 10; i++)
{
arr[i] = i;
#ifdef __DEBUG__
printf("%d\n", arr[i]);//为了观察数组是否赋值成功。
#endif //__DEBUG__
}
return 0;
}
5.6嵌套文件包含
为了避免头文件被多次使用
可以在开头写入
#ifndef __TEST_H__
#define __TEST_H__
//头⽂件的内容
#endif //__TEST_H__
或是
#pragma once