1.预定义符号
C语言设置了一些预定义符号,可以直接使用,预定义符号也是在预处理期间处理的。
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义
关于这几串预定义符号怎么用下面我给出例子我们来看一下:
#include <stdio.h>
{printf("%s\n",__FILE__);printf("%s\n",__DATE__);printf("%s\n",__TIME__);printf("%d\n",__LINE__);return 0;
}
我们可以根据 ,这些预定义符号的说明来理解他们的作用。我们创建的test.c文件他的源文件,文件当前的行号和文件被编译的日期和时间都被打印出来了。
那这个__STDC__这个符号是什么意思呢?我们再来看一下:
但是我们换成gcc的编译器可以得到下面的情况:
这就说明gcc是支持ANSIC
2.#define定义常量
#define有两个作用:
1.#define定义符号(常量)
2.#define定义宏
那我们看一下#define怎么定义常量的,下面给出个模型:
#define name stuff
先是#define ,然后加上符号名后面在是它的内容。
我们接下来看一下怎么用#define定义常量
看到了没有,最终关键字都会被内容替换掉。
下面我在给出几个例子我们来看一下:
#define MAX 1000\\定义一个MAX,他的值是一千,这就是一个符号的定义
#define reg register //为register这个关键字,创建一个简短的名字
#define do_forever for(;;) //用更形象的符号来替换一种实现
#define CASE break;case //再写case语句的时候自动把break写上
//如果定义的stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)
#define DEBUG_PRINT printf("file:%s\tline:%d\t \ date:%s\ttime:%s\n" ,\ __FILE__,__LINE__ , \__DATE__,__TIME__ )
我们抽出一个#define定义的常量来看一下
#define do_forever for(;;)
//我们可以看到这里的for(;;)初始化部分,调整部分,判断部分都可以省略掉
//但是判断部分如果省略掉不写的话,就意味着判断条件恒为真,就会造成死循环。
我们要考虑一个问题就是关于define定义标识符的时候,要不要考虑在最后加上;?
就像这样:
#define MAX 1000;
#define MAX 1000
建议不要加上 ; ,这样容易导致问题。
比如下面的场景:
#define MAX 1000//如果不加分号的话MAX被替换下来就是1000
int main()
{
int a = MAX;//int a = 1000;就是这样
}#define MAX 1000;//如果加分号的话MAX被替换下来就是1000;
int main()
{
int a = MAX;//int a = 1000;;就像是这样,这就成了两条语句了,这显然不正确
}
下面我在给说一个非常明显的错误
# define MAX 1000;//如果我们在最后带上了分号
int main()
{int m = 0;if(1)m = MAX;//当这里的MAX被替换了之后就成这样了:m = 1000;;这时就成为了两条语句了,但是我们都知道如果没有大括号的时候,if后面只能有一条语句,所以这里会出现语法错误。elsem = -1;
return 0;
}
3.#define定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)
下面是宏的申明方式:
#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
这里我们需要注意的是:
参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。就类似于#define定义常量。
下面关于宏我们来举上一个例子:实现一个宏,求一个数的平方
那这串代码怎么进行的? 就像上面说的:允许把参数替换到文本中
结合上面这串代码就是把x替换成a
结果就是这样。
但是这样写会有一种错误就是这样的
按理来说a+1是6结果应该等于36,但是为什么是十一呢?
所以我们可以知道:宏的参数不会进行计算,只是单纯的替换,预处理之后就是这样:
就想这样只进行了替换,所以结果是十一。
这里还有一个宏定义:
#define DOUBLE(x) (x) + (x)
定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。
int a = 5;
printf("%d\n" ,10 * DOUBLE(a));
那这串代码打印出来会是什么呢?我们感觉会是100,但是结果就是55,为什么呢?
因为乘法运算先于宏的加法,所以出现了55。那怎么办呢?
这个问题的解决办法是在宏定义表达式两边加上一对括号就可以了。就想这样:
#define DOUBLE(x) ( ( x ) + ( x ) )
提示:
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。
4。带有副作用的宏参数
举一个很简单的例子就是下面的这串代码:
这个就是带有副作用的,因为在++b之后虽然a已经成为11了,但是b的结果也变了。
MAX宏可以证明具有副作用的参数所引起的问题:
写一个宏,求两个数的较大值
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
int main()
{int a = 3;int b = 5;int m = MAX(a,b);printf("%d\n",m);return 0;
}
这串代码结果就是5,这串代码没有副作用,那我们把他变一下:
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
int main()
{int a = 3;int b = 5;int m = MAX(a++,b++);
//替换之后就是这样的int m = ( (a++) > (b++) ? (a++) : (b++) )后置++,先用在++
//首先先是a++和b++的比较但是是先比较在++。3大于5这个是错的,比完之后a为4,b为6,因为是错的所以?后面的a++是不用计算的,之后就是b++,所以m就是6,之后b在加1,b就成为了7 printf("m = %d\n",m);printf("a = %d\n",a);printf("b = %d\n",b);
//所以结果就是m = 6 a = 4 b = 7
return 0;
}
所以结果就是m = 6 a = 4 b = 7
这就是带有副作用的宏参数。