GCC 预定义宏:解锁编译器的隐藏信息
在 GCC 编译器中,有许多内置的预定义宏,它们可以提供编译环境的信息,如文件名、行号、时间、版本等。这些宏在调试、日志记录、条件编译等场景中非常有用。本文将介绍常见的 GCC 预定义宏,并提供示例代码及其输出结果。
1. 文件与函数信息宏
这些宏提供了代码的文件名、行号、函数名等信息,常用于日志记录和调试。
1.1 __FILE__ - 获取当前源文件名
 
表示当前源文件的名称(字符串)。
示例:
#include <stdio.h>int main() {printf("File: %s\n", __FILE__);return 0;
}
 
可能的输出:
File: main.c
 
1.2 __LINE__ - 获取当前行号
 
表示当前代码的行号(整数)。
示例:
#include <stdio.h>int main() {printf("Line: %d\n", __LINE__);return 0;
}
 
可能的输出:
Line: 4
 
(实际行号取决于代码所在位置)
1.3 __FUNCTION__ / __func__ - 获取当前函数名
 
在 C99 及更高版本中,__FUNCTION__ 和 __func__ 都可以获取当前函数的名称,__func__ 是更标准的写法。
示例:
#include <stdio.h>void test() {printf("Function: %s\n", __func__);
}int main() {test();return 0;
}
 
可能的输出:
Function: test
 
2. 编译时间信息宏
这些宏提供编译时的日期和时间,常用于生成版本信息或调试日志。
2.1 __DATE__ - 获取编译日期
 
格式:"Mmm dd yyyy",如 "Mar 21 2025"
示例:
#include <stdio.h>int main() {printf("Compiled on: %s\n", __DATE__);return 0;
}
 
可能的输出:
Compiled on: Mar 21 2025
 
2.2 __TIME__ - 获取编译时间
 
格式:"hh:mm:ss",如 "21:30:00"
示例:
#include <stdio.h>int main() {printf("Compiled at: %s\n", __TIME__);return 0;
}
 
可能的输出:
Compiled at: 21:30:00
 
3. 条件编译相关宏
这些宏可用于检查编译器的特性、语言标准和目标平台,以实现兼容性处理。
3.1 __STDC__ - 判断是否为标准 C 编译器
 
如果编译器遵循 ANSI C 标准,则此宏定义为 1。
示例:
#ifdef __STDC__printf("This is an ANSI C compiler\n");
#endif
 
3.2 __STDC_VERSION__ - 检查 C 语言标准版本
 
表示 C 语言标准的版本号,例如:
199409L(C90)199901L(C99)201112L(C11)201710L(C17)
示例:
#if __STDC_VERSION__ >= 201112Lprintf("C11 or later is supported\n");
#endif
 
3.3 __cplusplus - 检查是否为 C++ 编译
 
如果使用 C++ 编译器,该宏会被定义,且值表示 C++ 标准的版本号,如:
199711L(C++98)201103L(C++11)201402L(C++14)201703L(C++17)
示例:
#ifdef __cplusplusprintf("This is a C++ compiler\n");
#endif
 
4. 编译器与平台信息宏
4.1 __GNUC__ - 检查是否使用 GCC 编译器
 
如果使用 GCC 编译器,则此宏被定义,其值为 GCC 主版本号。
示例:
#ifdef __GNUC__printf("Compiled with GCC %d\n", __GNUC__);
#endif
 
可能的输出(GCC 13.1 编译时):
Compiled with GCC 13
 
4.2 __linux__ - 检查是否在 Linux 上运行
 
如果目标系统是 Linux,则此宏被定义。
示例:
#ifdef __linux__printf("Running on Linux\n");
#endif
 
4.3 __x86_64__ - 检查是否是 64 位架构
 
如果目标架构是 64 位 x86,则此宏被定义。
示例:
#ifdef __x86_64__printf("64-bit architecture\n");
#endif
 
5. 其他实用宏
5.1 __COUNTER__ - 递增的唯一标识符
 
此宏从 0 开始,每次使用时加 1,常用于生成唯一变量名。
示例:
#include <stdio.h>#define UNIQUE_NAME(x) x##__COUNTER__int UNIQUE_NAME(var) = 10;
int UNIQUE_NAME(var) = 20;int main() {printf("Unique variables defined.\n");return 0;
}
 
编译后变量名可能变为 var0 和 var1,避免了名称冲突。
5.2 __BASE_FILE__ - 获取主编译文件
 
如果某个文件是通过 #include 包含进来的,而不是直接编译的源文件,那么 __FILE__ 会显示该文件名,而 __BASE_FILE__ 会显示实际的主编译文件。
示例:
printf("Base file: %s\n", __BASE_FILE__);
 
6. 综合示例:获取编译信息
#include <stdio.h>int main() {printf("File: %s\n", __FILE__);printf("Line: %d\n", __LINE__);printf("Compiled on: %s at %s\n", __DATE__, __TIME__);#ifdef __GNUC__printf("GCC version: %d.%d\n", __GNUC__, __GNUC_MINOR__);#endifreturn 0;
}
 
可能的输出:
File: main.c
Line: 5
Compiled on: Mar 21 2025 at 21:30:00
GCC version: 13.1
 
7. 结论
这些 GCC 预定义宏在调试、日志、条件编译等场景中非常实用。建议在编写可移植代码时,合理利用这些宏来增强代码的灵活性和可读性。