当前位置: 首页 > news >正文

GCC 预定义宏:解锁编译器的隐藏信息

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__ >= 201112L
  printf("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 __cplusplus
  printf("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;
}

编译后变量名可能变为 var0var1,避免了名称冲突。


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__);
  #endif

  return 0;
}

可能的输出:

File: main.c
Line: 5
Compiled on: Mar 21 2025 at 21:30:00
GCC version: 13.1

7. 结论

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

相关文章:

  • 使用Docker运行 Ollama本地部署 DeepSeek 模型并用Dify实现可视化操作
  • 使用DeepSeek查找资料:C++ sprintf % 种类
  • 视频剪辑行业的现状与进阶之路:一个双视角分析
  • 《Android 13深度定制:手势拦截技术实现SystemUI状态栏智能折叠方案》
  • Java-校验值区间值的连续性
  • 每天学一个 Linux 命令(6):shutdown
  • Java八股
  • 【设计模式】三十二、策略模式
  • buu-bjdctf_2020_babystack2-好久不见51
  • Nodejs 项目打包部署方式
  • 博客系统自动化测试报告
  • Java实现十大经典排序算法详解
  • firefly经典蓝牙和QProcess记录
  • MinIO
  • 使用 Apktool 反编译、修改和重新打包 APK
  • 1978-2022年全国及31省农业机械总动力数据(无缺失)
  • 开源ORB_SLAM2项目编译常见问题与应对办法
  • 分布式(一):CAPBASE理论
  • Excel(实战):INDEX函数和MATCH函数
  • QSettings修改配置后强制重启应用导致配置文件大小为0问题
  • 订婚不等于性同意!山西订婚强奸案入选最高法案例
  • 博柏利上财年营收下降17%,计划裁员1700人助推股价涨超18%
  • 市场监管总局召开平台企业支持个体工商户发展座谈会
  • 新华时评:中美经贸会谈为全球经济纾压增信
  • 《审判》|“被告”的魅力:K在等什么?
  • 马上评丨摆摊要交芙蓉王?对吃拿卡要必须零容忍