目录
一:预定义符号
C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ASIC C,其值为1,否则未定义
//ASIC C gcc编译器是支持的,但是VS不支持
二:#define定义常量
基础:语法:
#define name stuff
#define MAX 1000
#define reg register //为register这个关键字,创建一个更简短的名字
//for循环判断部分什么都不写,表示恒成立,死循环
#define do_forver for(;;) //用更形象的符号来替换一种实现
#define CASE break;case//在case语句自动把break加上
//如果定义的stuff太长,可以分成几行写,除了最后一行,每行的后面都加上一个反斜杠(续行符)
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
date:%s\ttime:%s\t, \
__FILE__,__LINE__,\ // \后面不能有空格,直接按空格
__DATE__,__TIME__)
思考:在define定义标识符时,要不要在最后加上;?
比如:
#define MAX 1000;
#define MAX 1000
建议不要加上;,这样容易出问题
比如以下场景:
if(condition)
max = MAX;
else
max = 0;
如果定义MAX时用第一种加上分号的,等替换了以后就会变成max = MAX;;,if和else之间就是两条语句,而没有大括号的时候,if后面只能有一条语句。这里会出现语法错误。
三:#define定义宏
#define机制包含了一个规定,允许把参数替换到文本中,这种实现通常称为宏(有参数),或者定义宏
下面是宏的申明方式:
#define name(parament-list) stuff
// 参数 内容
其中parament-list是一个由逗号隔开的符号表,它们可能出现在stuff中
注:
参数列表的左括号必须name紧邻。如果两者之间有任何空白,参数列表就会解释为stuff的一部分
举例:
写一个宏,求平方
#define SQUARE(x) x*x
这个宏接受一个参数x,如果上述声明以后,你把SQUARE(5)置于程序中,预处理器就会用下面这个表达式替换上面的表达式:5*5
警告:
这个宏存在一定的问题:
看下面的代码段:
int a = 5;
printf("%d\n", SQUARE(a+1) );//宏的参数不计算,直接传到表达式中
第一眼时,也许大多数人认为就是5+1=6,算的是6的平方,结果是36啊
但是结果是11,这是为什么呢?
替换文本时,参数x被替换成a+1,所以这条语句实际上变成了
printf("%d",a + 1 * a + 1);
这样就可以清晰的看出,由替换产生的表达式并没有按照预想的次序求值。
在宏定义上加上了两个括号,这个问题便轻松解决了:
#define SQUARE(x) (x) * (x)
这样的处理之后就产生了预期的处理
printf("%d",(a+1) * (a+1) );
这里还有另一个宏定义:
算一个数的二倍:
#define DOUBLE(x) (x) + (x)
定义中我们用了括号,避免了之前出现过的问题,但是这个宏可能出现新的错误
int a = 5;
printf("%d" ,10* DOUBLE(a) );
有没有觉得结果是100的?但是实际上打印的结果是55。
替换之后的样子是:
printf("%d", 10*(5)+(5) );
乘法运算大于宏定义,所以出现了55。
这个问题的解决办法是在宏定义表达式两边加上一对括号就可以了。
#define DOUBLE(x) ( (x) + (x) )
提示:
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏定义时参中的操作符或邻近操作符之间不可预料的相互作用。