1 预定义宏
__DATE__、__FILE__、__LINE__、__TIME__、__func__。
其实预定义宏不止这些,不过这里我们就只介绍这些。
1.1 什么是预定义宏
预定义宏,也可以称为编译器内置宏,这个宏并没有定义在哪个.h文件中,所以不能再哪个.h中找到这些玩意。
进行预编译时,当预编译器看到这些玩意时,会自动处理这些预定义宏。
其实将这些预定义宏称为预编译关键字,可能更好些。
1.2 作用
(1)__DATE__:代表预处理的日期
当预处理器检测到__DATE__后,会将其替换为"月 日 年"的字符串形式的时间,时间格式是西方人习惯的格式。
(2)__FILE__:代表当前预编译正在处理的那个源文件的文件名
当预处理器检测到__FILE__后,会将其替换为"***.c"的文件名。
(3)__LINE__:代表__LINE__当前所在行的行号
当预处理器检测到__LINE__后,会将其替换为__LINE__当前所在行的行号(整形)。
(4)__TIME__:代表对源文件进行预编译时的时间
当预处理器检测到__TIME__后,会将其替换为“hh:mm:ss”格式的时间。
(5)__func__:当前__func__所在函数的函数名
不过这个在预编译阶段不会被处理,而是留到编译阶段处理。
(6)例子
helloworld.c
#include <stdio.h> int main(void) { printf("预编译的日期:%s\n", __DATE__); printf("预编译的文件:%s\n", __FILE__); printf("当前所在行号:%d\n", __LINE__); printf("预编译的时间:%s\n", __TIME__); printf("当前所在函数:%s\n", __func__); return 0; }
查看预编译结果:
int main(void) { printf("预编译的日期:%s\n", "Jul 5 2018"); //替换为了日期 printf("预编译的文件:%s\n", "helloworld.c"); //替换为了文件名 printf("当前所在行号:%d\n", 7); //替换为了__LINE__所在的行号 printf("预编译的时间:%s\n", "02:21:08"); //替换为了预编译的时间 printf("当前所在函数:%s\n", __func__);//没有替换,到第二阶段编译时再处理,__func__代表的函数名是main return 0; }
打印结果:
预编译的日期:Jul 5 2018 预编译的文件:helloworld.c 当前所在行号:7 预编译的时间:02:28:15 当前所在函数:main
除了__func__外,其它几个都可以定义相应的变量来存放,比如。
int line = __LINE__; char date[] = __DATE__;
1.3 预定义宏的意义 与 调试宏
(1)意义
常常用于调试打印、跟踪代码用。
当一个程序写大了后,在调试程序的功能性错误时,往往需要打印信息来跟踪代码,看看程序是运行到什么位置时才出现了功能性错误,以方便我们调试。
printf("%s %d %s\n", __FILE__, __LINE__, __func__);
当然如果不需要显示文件名和函数名的话,其实直接打印行号就可以了。
printf("%d\n", __LINE__);
(2)调试宏
在每个需要打印的地方都写printf会非常的麻烦,因此我们可以把它写成调试宏。
1)例子:
#include <stdio.h> //调试宏,DEBUG的名字可以自己随便起 #define DEBUG printf("%s %d %s\n", __FILE__, __LINE__, __func__); void exchange(int *p1, int *p2) { DEBUG int tmp = 0; DEBUG tmp = *p1; DEBUG *p1 = *p2; DEBUG *p2 = tmp; DEBUG } int main(void) { int a = 10; int b = 30; DEBUG exchange(&a, &b); DEBUG printf("a=%d, b=%d\n", a, b); DEBUG return 0; }
通过打印信息来跟踪程序,其实有些时候比“单步运行调试”更好用,因为单步运行调试在某些情况其实很麻烦,不如打印信息来的好使。
2)如果你想打印自定义信息的话,我们还可以将调试宏定义为带参宏
#define DEBUG(s1, s2) printf(s1, s2);
在程序中使用时,可以指定你要任何打印的调试信息。
DEBUG("%d\n", va); //你想写什么,可以由你自己决定。 DEBUG("%s\n", str);
疑问:感觉这也不比直接写printf("%d\n", va)更方便呀?
不直接使用printf,而是写成DEBUG(s1, s2)带参宏的形式,可以方便我们使用“条件编译”来快速打开和关闭调试宏,后面将再介绍这个问题。