AI智能摘要
C/C++预定义宏是由编译器预处理器定义的特殊标识符,名称均以双下划线开头和结尾且通常大写,不可被取消或重新定义,使用需包含头文件。常用宏包括__DATE__(编译日期)、__TIME__(编译时间)、__FILE__(源文件名)、__LINE__(当前行号)、__FUNCTION__(函数名)、__STDC__(ANSI C标准支持)及__STDC_VERSION__(C标准版本)。这些宏用于获取编译信息、实现跨平台兼容(如通过__STDC_VERSION__适配不同编译器版本)以及辅助调试(如结合__FILE__和__LINE__进行异常跟踪),能有效提升代码可维护性和错误排查效率。
— 此摘要由AI分析文章内容生成,仅供参考。
![]()
1 预定义宏是什么
为了方便处理一些有用信息,C/C++编译器中的预处理器会定义一些预处理标识符,也就是预定义宏。这些宏定义不仅可以帮助完成源码的跨平台编译,灵活使用也可以巧妙地输出非常有用的调试信息,其具有以下特点:
- 预定义宏的名称都是以“__”(两条下划线)开头和结尾的,并且通常由大写字符组成
- 预定义宏不能被取消定义(#undef)或被编程人员重新定义
- 使用预定义宏需要包含头文件<stdio.h>
2 常用的预定义宏
下表列举了一些在C/C++编程中常用的预定义宏:
| 预定义宏 | 含义 |
|---|---|
| __DATE__ | 源文件的编译日期,以“Mmm dd yyy”形式的字符串常量表示 |
| __TIME__ | 源文件的编译时间,以“hh:mm:ss”形式的字符串常量表示 |
| __TIMESTAMP__ | 源文件的编译时间戳,以字符串常量表示 |
| __FILE__ | 源文件的名称,以字符串常量表示 |
| __LINE__ | 源文件中正被编译的行号,以十进制整型常量表示 |
| __VERSION__ | 编译器的版本,以字符串常量表示 |
| __STDC__ | 若当前编译器严格遵循 ANSI C 标准,则该宏值为1,否则未定义 |
| __STDC_VERSION__ | 若编译器标准符合C89,该宏值为199409L; 若编译器标准符合C99,该宏值为199901L; 若编译器标准符合C11,该宏值为201112L |
| __FUNCTION__ | 其展开为当前函数名,以字符串常量表示(函数作用域) |
3 预定义宏的用例
3.1 确定程序的编译时间
利用“__DATE__”和“__TIME__”预定义宏可以确定程序的编译时间,示例代码如下:
int main (void)
{
printf("www.nixinglong.com\n"); // N1XON's personal website
printf("Compiled on %s at %s\n", __DATE__,__TIME__);
return 0;
}
3.2 兼容不同版本的编译器
利用“__STDC__”与“__STDC_VERSION__”预定义宏可以编写兼容不同版本编译器的程序,示例代码如下:
#ifdef __STDC__ /* Some version of standard C */ #if defined(__STDC__VERSION__)&&__STDC_VERSION__>=199901L /* C99 */ #elif defined(__STDC_VERSION__)&&__STDC_VERSION__>=199409L /* C89 and amendment 1 */ #else /* C89 but not amendment 1*/ #endif #else /* __STDC__not defined */ /*Not Standard C*/ #endif
3.3 异常跟踪
利用”__FILE__”、”__LINE__”与”__FUNCTION__”预定义宏,可以方便的在调试程序时对程序运行异常进行跟踪,示例代码如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define MESSAGE(message,assertion) \
do{\
if(!(assertion)){\
printf("line %d in %s(%s)", __LINE__, __FILE__,__FUNCTION__);\
if(message){\
printf(":%s",message);\
}\
printf("\n");\
abort();\
}\
}while(0)
int OpenFile(const char *filename)
{
int fd;
MESSAGE("文件名称不能够为空",filename);
MESSAGE("文件不存在",0==access(filename,F_OK));
fd = open(filename,O_RDONLY);
close(fd);
return 0;
}
int main(int argc,char **argv)
{
MESSAGE("命令参数不能够为空",argc==2);
OpenFile(argv[1]);
return 0;
}
__LINE__太香了,定位bug直接省一半时间😂
以前就知道__FILE__,没想到__TIMESTAMP__还能拿来判断热更新版本,新技能get
想知道这些宏在arm交叉编译时会不会值不一样?有踩坑过的老哥吗