预处理详解
预定义符号
时间,文件名等等
常量定义
常量定义纯属是文本替换
#define M 100
#define STR “hehe”
define 可以做很多有趣的文本替换,可以简化代码书写的复杂
define 太长可以用续行符
define 后面不要加分号(因为define是文本替换)
宏定义
#define name(parament-list) stuff
ex: #define SQUARE(x) x*x
允许把参数替换到文本之中
宏定义可能出现问题
printf("%d\n" ,SQUARE( a + 1) );
纯粹的文本替换会忽略掉整体性,从而在计算顺序上出现问题
解决方法:在需要整体性的地方全部加上括号
1 在运算过程中加上括号
2 运算结果加上括号
ex:二倍
define DOUBLE(X) ((X)+(X))
以上宏定义是合理的
宏的副作用
对于x++,且在宏定义中参数多次出现,x++会多次计算,带来不可估量的后果
宏替换的规则
- 先对参数进行替换
- 再对宏进行替换
ex: MAX(M,3+5)
MAX 也是一个宏定义
先替换M,再替换MAX - 宏可以嵌套但是不可以递归
#和##的运用
#用于把宏参数变成字符串
eg:==#define PRINT(n) printf("the value of "**#n** " is %d", n);==
#define PRINT(val) printf("the value of "#val" is "%d",val)
把val转换为对应的字符串,而非值!!
##用于文本的连接,连接为一个标识符
#define GENERIC_MAX(type)
eg:
宏定义函数模板,要用续行符
type type##_max(type x, type y)\ { \ return (x>y?x:y); \ }
type为int 则函数名为int_max
type为double 则函数名为double_max;
undef
用于移除宏定义
条件编译
可以根据是否有宏定义选择在什么时候编译,什么时候不编译
- #ifdef #ifndef 判断是否被定义 定义过这个符号才参与编译。
- #if #elif #else判断条件
只有满足特殊条件才被编译。
宏定义与函数
- 函数需要调用,宏内嵌
- 宏更加灵活,可以是数字,也可以是字符,适用于小型的运算,运算速度快,效率高。重复使用会增加程序长度。
- 函数适用于大型运算,节省空间,调用的时候才占用对应的栈空间。
- 注意:函数可以调试,参数无法调试
- 宏没有具体参数类型,灵活但是不够严谨,容易出现错误
- 宏是纯文本替换,可能出现运算顺序的问题
- 宏可能出现严重的副作用,可能会多次求值,结果无法预料
命令行定义
指令 -D
int array [ARRAY_SIZE];
gcc -D ARRAY_SIZE=10 program.c
可以在编译的时候定义宏,用于生成不同的程序版本,适应不同的硬件设施
#pragma once
这条指令可以防止重复包含头文件,减少编译的压力。
命名约定
宏往往大写
函数小写