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 预定义宏在调试、日志、条件编译等场景中非常实用。建议在编写可移植代码时,合理利用这些宏来增强代码的灵活性和可读性。