
# C 语言 —— 预处理
# #error
// 编译程序时,只要遇到 #error 就会生成一个编译错误提醒,并且停止编译,语法格式:#error error-message实例:#ifdef xxx#error “xxx has been defined”#else#endif
# #ifndef #define #endif
// 当项目中有多个 c 文件使用到同一个头文件是,在编译的时候会出现大量的变量,函数声明冲突,解决就是使用#ifndef _HEAR_H_#define _HEAR_H_#endif
# #define 和 const
Define 和 const 都可以用于定义常量但以下区别 (生效时间,内存占用情况,类型检查):
- define 只是单纯的文本替换,define 常量的生命生命周期止于编译器,不存在分配内存,存在与程序的代码段
- const 生效于编译的阶段;define 生效于预处理阶段
- Const 修饰的常量处于程序的数据段,在堆栈中分配空间
- Const 有数据类型检查,define 没有
- #define 不可调试,const 能调试
- const 定义的变量在 C 中不是真正的常量
- Const 定义的常量不能作为数组的大小
# typedef 和 #define
原理不同:
- 首先 #define 是预处理命令,在预处理阶段只是机械的替换带入字符串,并不会左类型检查,
- typedef 是关键字,作用是给自己的作用域内给一个已经存在的类型起个别名
- #define 没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用,而 typedef 有自己的作用域
- 对指针的操作不同
# #define
表明一年
#define YEAR (60 * 60 * 24 * 365)ul标准宏 MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))缺点
- 无法进行类型检查
- 运算优先级问题
- 无法调试
- 代码膨胀
- 无法操作类的私有数据成员
#define m(a,b) a*b// #define m (a,b) (a)*(b)// 避免出问题最好加上 () int main(){ printf("%d\n",m(5,6)); printf("%d\n",m(5+1,6));// 实际是这样的:5+1*6 return 0;}#define sqort(a) ((a)*(a))// 实例 1: int a = 5; int b = sqort(a++);//((a++) * (a++) ) 先给括号赋值 5 之后 a 再 + 1=6 printf("%d\n",b);//30 printf("%d\n",a);//7// 实例 2: int a = 5; int b = sqort(++a);//((++a)* (++a)) printf("%d\n",b);//49 printf("%d\n",a);//7这里主要是考察++a和后加加的问题// 记住一点: ++a返回的a的引用,a++返回的是a加之前的数值 a的引用是要等最终的那个a才能确定的
# #include
对于.#include <头文件>,表示是系统文件,编译会先从标准库路径下搜索,编译器设置的头文件路径 --> 系统变量
对于 #include” 头文件”,当前头文件目录 --> 编译器设置的头文件路径 --> 系统变量
# C 代码编译过程
- 预处理(Preprocessing):
- 预处理阶段是在实际编译之前的一个可选步骤,用于处理源代码中的预处理指令,比如
#include和#define。- 预处理器将处理这些指令,并且可能会包含其他文件、进行宏替换等。
- 预处理的输出是一个经过处理的源文件,通常以
.i或.ii为扩展名。
- 编译(Compiling):
- 编译阶段将预处理后的源代码转换为汇编代码(Assembly Code)。
- 编译器(如 GNU Compiler Collection 中的
gcc)将 C 源代码翻译成汇编语言。- 输出是一个以
.s为扩展名的汇编代码文件。
- 汇编(Assembling):
- 汇编阶段将汇编代码转换为机器语言指令。
- 汇编器(如 GNU Assembler 中的
as)将汇编代码翻译成机器码。- 输出是一个以
.o或.obj为扩展名的目标文件,包含了二进制指令。
- 链接(Linking):
- 链接阶段将多个目标文件(例如,多个 C 文件分别编译得到的目标文件)合并为一个可执行文件。
- 链接器(如 GNU 的
ld或gcc中的链接器部分)将各个目标文件中的函数和变量引用解析,并创建一个可执行文件。- 链接的输出是一个可执行的二进制文件,可以在操作系统上运行。
# 在头文件中是否可以定义静态变量
不可以,因为静态变量是有记忆的,不会随函数结束而结束,所以,如果定义在头文件中,那么就会被多个文件开辟空间,浪费资源或者重新出错
# #和 ## 的作用
// #利用宏参数字符串化#define ARGV(x) printf(""#x" is %s\n",#x) // 表示把参数 x 解释为字符串 int a = 5; ARGV(a); //a is a// ## 运算符粘合剂 组合成一个变量,强制分隔#define targ( n ) X##n // 表示 X1...... 或 Xn int main(){ int a = 5;// ARGV(a); int targ(1) = 10;// 表示 X1 =10 printf("%d\",X1);//10 return 0}