预处理
预定义符号
符号 | 作用 |
---|---|
_FILE_ | 进行编译的源文件 |
_LINE_ | 文件当前的行号 |
_DATE_ | 文件被编译的日期 |
_TIME_ | 文件被编译的时间 |
_STDC_ | 如果编译器支持ANSI C,其值为1,否则未定义 |
例子🌰
#define
#define 定义标识符
语法:
#define name stuff
例子🌰
#define MN 78
#define reg register //为register替换一个简短的名字
注意:#define
定义标识符的时候,最后不要加;
否则容易出现以下问题:
#define 定义宏
#define 具有类似函数的功能,可以把参数替换到文本中,这种实现通常称为宏或定义宏。
语法:
#define name( parament-list ) stuff
parament-list
中填写参数,用逗号隔开,与函数不同的是,不用写其类型。
注意:参数列表的左括号必须与name紧邻,不能有空格。否则参数列表也会被当成stuff
例子🌰
#define MAX(x, y) x > y ? x : y
int main()
{
int a = 10;
int b = 20;
printf("%d", MAX(a, b));
return 0;
}
#define
的本质是替换,代码中的MAX(a, b)
实际被替换成了a > b ? a : b
#define与typedef
例子🌰
#define type1 int*
typedef int* type2;
int main()
{
type1 a, b;
type2 c, d;
return 0;
}
问:a b c d
哪些不是指针变量?
答:b,因为#define本质是替换,相当于int* a, b
其中b不是指针变量。
既然只是替换,那么可能出现以下问题
#define MUL(x, y) x * y
int main()
{
printf("%d", MUL(2 + 3, 3 + 2));
return 0;
}
可能我们本意上希望实现5 * 5
,实际上替换后变成了2 + 3 * 3 + 2
容易因为运算符优先级的问题造成混乱。
所以有必要为每个参数以及整体加上括号#define MUL(x, y) ((x) * (y))
总结与注意:
- 宏不能递归
- 宏的执行速度较函数更快,因为函数调用需要时间。
- 函数参数有类型检查,宏参数没有
- 由于宏是通过替换完成的,所以操作符的优先级会影响宏的求值,应尽量使用括号明确优先级
小题:
用尽可能少的代码实现将一个整数的二进制位的奇数位和偶数位交换。
答案:
#define SWAP(x) (((x) & 0x55555555) << 1 | ((x) & 0xaaaaaaaa) >> 1)
0x55555555
就是二进制0101 0101 0101 0101 0101 0101 0101 0101
和x按位与可以筛选出x的奇数位,同理,0xaaaaaaaa
可以筛选出偶数位,分别左右移再按位或即可得到答案。