1.预处理指令:#define与#undef,#include
2.宏和函数的区别
3.预处理操作符#与##
4.条件编译
预处理阶段,预处理器查找一行中以#
号开始的预处理指令。ANSI和后来的标准都允许#
号前面有空格或制表符,而且还允许在#
和指令的其余部分之间有空格
1.1#define(标识符,宏)
定义标识符:可以通过#define定义一些标识符常量,如,数字,字符,字符串,甚至循环;
例如:
注:当用#define定义标识符时,在定义的标识符后不要在其后加分号;
例如:
宏定义:#define机制包括了一个规定,允许把参数替换到文本,这种实现通常称为宏,或者定义宏;注:参数列表的左括号必须与宏定义的名字紧邻;
例:用宏定义一个简单的数乘数;
#define 宏定义:
#define mul(x) x*x
int main()
{
printf("%d\n", mul(5));
}
这个宏乍一看没有问题,但是当宏参数不再是单纯的数而是表达式时,这个时候会出现由于运算优先级发生错误;
//#define 定义宏时产生的算术优先级错误:
// 1.乘法错误:
//#define mul(x) x*x
//int main()
//{
// printf("%d\n", mul(5 + 1));//以为宏定义将参数整体代入得到(5 + 1)*(5 + 1),预期输出为36;
// printf("%d\n", 5+1*5+1);// 但是由于乘法算术优先级大于加法,所以(5 + 1)*(5 + 1)被解析成5+1*5+1=11;结果输出为11;
// return 0;
//}
//
// 解决方法:
//#define mul(x) (x)*(x)
//int main()
//{
// printf("%d\n", mul(5 + 1));
// printf("%d\n",(5+1)*(5+1));//将宏定义的参数表达式加上括号,则解决了因为乘法优先级的问题;结果输出为36;
//
// return 0;
//}
//2.加法错误:
//#define mul(x) (x)+(x)
//int main()
//{
// printf("%d\n", 10 * mul(5 + 1));//以为宏定义将参数整体代入得到10乘以表达式(5 + 1)+(5 + 1)的和12,预期输出为120;
// printf("%d\n", 10 * (5 + 1) + (5 + 1));// 但是由于乘法算术优先级大于加法,所以10先乘了一个(5+1),再加上一个(5+1),结果输出为10*6+6=66;
//
// return 0;
//}
// 解决方法:
//#define mul(x) ((x)+(x))
//int main()
//{
// printf("%d\n", 10 * mul(5 + 1)); //将宏定义的整体参数表达式加上括号,则解决了因为乘法优先级的问题;先算括号内的参数表达式,最后在算大括号外面的运算;
// return 0;
//}
所以,在用于对较简单的数值表达式进行的宏定义都应该用上 ((x)+(x))这种方式加上括号,避免在使用宏时由于参数中的操作符或领近操作符之间不可预料的相互作用;
带副作用的宏参数:
例如:
//#define CAT(x,y) ((x)>(y)?(x):(y))
//int main()
//{
// int a = 3;
// int b = 4;
// int c = CAT(++a, ++b);
// //int c=(a,b) ((++a)>(++b)?(++a):(++b)) //++a为3+1=4;++b为4+1=5;
// 所以宏定义此时为:参数:a=4;b=5 宏:((4)>(5)?(++4):(++5)) ;结果输出为6,b=6;a=4;
// printf("c=%d a=%d b=%d", c, a, b);
// 输出结果: c = 6; a=4; b=6;
// return 0;
//}
当宏参数在宏中出现的次数超过一次时,那么在使用宏时会出现一些危险,导致产生不是期望的值,副作用就是表达式求值的时候出现的永久性结果;例(x++,带有副作用,x+1,没有副作用)
1.2 #undef(取消定义宏)
//#undef:取消宏定义;
//#define MAX 10
//int main()
//{
// printf("%d\n", MAX);
//#undef MAX
// printf("%d\n", MAX);//取消宏定义,会报错未定义符号MAX;
// return 0;
//}
1.3#include (#include <.....>与 #include ".....")
1.如果是尖括号#include <.....>的头文件包含,编译器会直接去C语言库中寻找;
2。如果是双引号#include "....."的头文件包含,先会在源文件所在的目录下查找,如果找不到,再去C语言库中寻找,找不到就会提示编译错误
2.宏和函数的区别
主要总结于一张图,
3.预处理操作符#与##
3.1 #(可以把一个宏参数变成对应的字符串)
例:
//#define PRINT(val,format) printf("the value of"#val"is "format"\n",val)//#可以将一个宏参数转化为一个字符串,如#val转化为"val";
//int main()
//{
// int a = 10;
// //printf("the value of a is %d\n", a);
// PRINT(a, "%d");
// float b = 99.9f;
// //printf("the value of b is %.2f\n", b);
// PRINT(b, "%f");
// double c = 100.00;
// //printf("the value of c is %.2lf\n", c);
// PRINT(c, "%lf");
// return 0;
//}
3.2 ##(它允许宏定义从分离的文本片段创建标识符)
例:
4.条件编译(#if, #endif, #elif, #if define, #if !defined, #ifdef , #ifndef)
4.1 #if ,#endif;(单分支语句)
4.2 #if , #elif #endif;(多分支语句)
4.3 #if define().....#endif
!#if define().....#endif
4.4 #ifdef ......#endif
#ifndef......#endif
所以,综合4.3, 4.4可知,
#if defined(MAX)与#ifdef MAX相同;如果有定义宏,执行下一条程序;
#if !defined(MAX)与#ifndef MAX相同;如果没有定义宏,则不执行下一条程序;
至此,这是我对C语言预处理指令的大致理解,如有不足不到之处,请各位批评指教!