C语言——预处理
#error
1 2 3 4 5 6 7 8
// 编译程序时,只要遇到#error就会生成一个编译错误提醒,并且停止编译, 语法格式: #error error-message 实例: #ifdef xxx #error “xxx has been defined” #else #endif
#ifndef #define #endif
1 2 3 4
// 当项目中有多个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
表明一年
1
#define YEAR (60 * 60 * 24 * 365)ul
标准宏MIN
1
#define MIN(a, b) ((a) < (b) ? (a) : (b))
缺点
- 无法进行类型检查
- 运算优先级问题
- 无法调试
- 代码膨胀
- 无法操作类的私有数据成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
#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
中的链接器部分)将各个目标文件中的函数和变量引用解析,并创建一个可执行文件。- 链接的输出是一个可执行的二进制文件,可以在操作系统上运行。
在头文件中是否可以定义静态变量
不可以,因为静态变量是有记忆的,不会随函数结束而结束,所以,如果定义在头文件中,那么就会被多个文件开辟空间,浪费资源或者重新出错
#和##的作用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// #利用宏参数字符串化 #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 }