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

『 C 』 `##` 在 C 语言宏定义中的作用解析

文章目录

    • `##` 运算符的基本概念
    • 可变参数宏与 `##` 的应用
      • 可变参数宏简介
      • `##` 处理可变参数的两种情况
        • 可变参数列表为空
        • 可变参数列表不为空
    • 示例代码验证


在 C 和 C++ 编程里,宏定义是个很有用的工具。今天咱们就来聊聊 ## 这个预处理器连接运算符在宏定义中的作用,特别是在可变参数宏里的应用。

## 运算符的基本概念

## 是预处理器的连接运算符,也叫“令牌粘贴”运算符。它能把两个预处理令牌连在一起,变成一个新的预处理令牌。在宏定义里,它主要用于处理可变参数。这部分内容在 C 语言标准文档里有明确说明,它是 C99 及以后标准支持的特性。

可变参数宏与 ## 的应用

可变参数宏简介

C99 引入了可变参数宏的概念。在宏定义里,... 表示可变参数部分,__VA_ARGS__ 会被替换成实际传递的可变参数列表。比如下面这个 LOG 宏:

#define LOG(level, format, ...) { \
    if (level >= LDEFAULT) { \
        time_t t = time(NULL);\ 
        struct tm *lt = localtime(&t);\ 
        char time_tmp[32] = {0}; \
        strftime(time_tmp, 31, "%m-%d %T", lt);\ 
        fprintf(stdout, "[%s][%s:%d] " format "\n", time_tmp, __FILE__, __LINE__, ##__VA_ARGS__); \
    } \
}

## 处理可变参数的两种情况

可变参数列表为空

当调用 LOG 宏时没传递可变参数,像 LOG(LINF, "No variable arguments");## 能消除 __VA_ARGS__ 前面的逗号。要是没有 ##,宏展开后会有多余逗号,导致编译出错。有了 ##,可变参数为空时逗号会被移除,保证代码正确。

可变参数列表不为空

如果传递了可变参数,比如 LOG(LINF, "The sum is %d", a + b);##__VA_ARGS__ 会被替换成实际的可变参数 a + b,宏展开后就能正确把参数传给 fprintf 函数。

示例代码验证

下面是个简单示例,展示 LOG 宏的使用和 ## 的作用:

#include <stdio.h>
#include <time.h>

#define LDBG 0
#define LINF 1
#define LERR 2
#define LDEFAULT LINF

#define LOG(level, format, ...) { \
    if (level >= LDEFAULT) { \
        time_t t = time(NULL);\ 
        struct tm *lt = localtime(&t); \
        char time_tmp[32] = {0}; \
        strftime(time_tmp, 31, "%m-%d %T", lt);\ 
        fprintf(stdout, "[%s][%s:%d] " format "\n", time_tmp, __FILE__, __LINE__, ##__VA_ARGS__); \
    } \
}

int main() {
    int a = 10, b = 20;
    LOG(LINF, "Starting the program");
    LOG(LINF, "The sum of %d and %d is %d", a, b, a + b);
    return 0;
}

在这个示例中,第一个 LOG 调用没传可变参数,第二个传了。因为用了 ##,两种情况都能正确编译运行。

通过以上分析,我们能清楚看到 ## 运算符在处理可变参数宏时的重要性,它保证了代码的灵活性和正确性。希望大家在编程中能灵活运用这个特性。


http://www.kler.cn/a/529986.html

相关文章:

  • npm 和 pip 安装中常见问题总结
  • 【C++语言】卡码网语言基础课系列----13. 链表的基础操作I
  • Qt事件处理:理解处理器、过滤器与事件系统
  • C++模板初了解
  • C#面向对象(封装)
  • LeGO LOAM坐标系问题的自我思考
  • 2.[网鼎杯 2020 朱雀组]phpweb
  • Android 开发:新的一年,新的征程
  • 【5. C++ 变量作用域及其深入探讨】
  • 2 [GitHub遭遇严重供应链投毒攻击]
  • 城市道路车辆自行车摩托车公交车检测数据集VOC+YOLO格式5236张5类别
  • FlashAttention v1 论文解读
  • Word List 2
  • 二叉树——102,107,199,637
  • 云原生(五十三) | SQL查询操作
  • 机器学习--概览
  • 使用等宽等频法进行数据特征离散化
  • C++, STL容器 list:双向链表深度解析
  • MLM之MiniCPM-o:MiniCPM-o的简介(涉及MiniCPM-o 2.6和MiniCPM-V 2.6)、安装和使用方法、案例应用之详细攻略
  • 论文阅读:Realistic Noise Synthesis with Diffusion Models
  • 【B站保姆级视频教程:Jetson配置YOLOv11环境(六)PyTorchTorchvision安装】
  • 浅尝模型微调Getting Started
  • C语言教学第二课:变量与数据类型
  • UE学习日志#19 C++笔记#5 基础复习5 引用1
  • Vue.js组件开发-实现图片浮动效果
  • Docker 部署 Starrocks 教程