news 2026/4/16 15:22:19

C语言_X-Macro

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言_X-Macro

X-Macro (X宏)

X-Macro (X宏)我愿称为其为超级宏

是什么?

其将数据列表和命令分开,通过X宏你可以实现对同一组数据列表,执行不同命令的操作。其设计哲学类似于设备树,将描述数据与执行逻辑分开

什么用?

#define FOREACH_STATE(S) S(STATE_INIT), S(STATE_RUNNING),S(STATE_PAUSED)……

  1. 这是一个宏套宏,第一层宏为FOREACH_STATE(S)=后面一大串S(STATE_INIT), S(STATE_RUNNING)……。详见以下代码。
  2. 第二层宏为, S可以被外界选择为各种各样的命令操作。例见第二步的展开策略。
  3. 其中的S可以被其它任意字符代替,其只是一个形式参数
    • S:代表State(状态)或Symbol。
    • X:这是最经典的用法(也是X-Macros名称的由来)。
    • ENTRYITEM:为了让代码读起来更像人话。
#include<stdio.h>/* * X-Macro 技术演示程序 * * X-Macro 是一种 C 语言预处理器技术,通过宏定义来生成重复性代码 * 主要优势: * 1. DRY (Don't Repeat Yourself) 原则 - 避免代码重复 * 2. 单一数据源 - 所有数据结构从同一源头生成 * 3. 自动同步 - 添加新状态时,所有相关结构自动更新 * 4. 减少维护成本 - 修改只需在一处进行 *//* 1. 定义状态列表(唯一真相源) *///这是一个宏套宏,第一层为FOREACH_STATE(S)=后面一大串S(STATE_INIT), S(STATE_RUNNING)……//第二层宏为, S可以被外界选择为各种各样的命令操作。例见第二步的展开策略。#defineFOREACH_STATE(S)\S(STATE_INIT),/* 初始化状态 */\S(STATE_RUNNING),/* 运行状态 */\S(STATE_PAUSED),/* 暂停状态 */\S(STATE_STOPPED),/* 停止状态 */\S(STATE_FINISHED)/* 完成状态 *//* 2. 定义"展开策略" - 不同的数据生成方式 */#defineGENERATE_ENUM(a)a/* 直接使用枚举名称 */#defineGENERATE_ENUM_add(a)a+1/* 枚举值加1 */#defineGENERATE_STRING(s)#s/* 转换为字符串 */#defineGENERATE_STRING_end(s)#s"end"/* 转换为字符串并添加"end"后缀 *//* 3. 用同一份状态表生成 enum */enummy_state{FOREACH_STATE(GENERATE_ENUM)/* 展开为: STATE_INIT, STATE_RUNNING, ... */};/* 4. 用同一份状态表生成字符串数组 */staticconstchar*constmy_state_name[]={FOREACH_STATE(GENERATE_STRING)/* 展开为: "STATE_INIT", "STATE_RUNNING", ... */};/* 5. 用同一份状态表生成字符串数组,要求末尾加end */staticconstchar*constmy_state_name_end[]={FOREACH_STATE(GENERATE_STRING_end)/* 展开为: "STATE_INITend", "STATE_RUNNINGend", ... */};/* 6. 用同一份状态表生成整数数组,要求每个值加1 */staticconstintmy_state_add[]={FOREACH_STATE(GENERATE_ENUM_add)/* 展开为: 1, 2, 3, 4, 5 */};intmain(void){enummy_states;printf("X-Macro 技术演示 - 多种数据结构自动生成\n");printf("=============================================\n\n");/* * 遍历所有状态,展示从同一状态源生成的不同数据结构 * 注意:由于使用了 X-Macro,所有数组的大小和索引都是自动同步的 */for(s=STATE_INIT;s<=STATE_FINISHED;s++){/* 显示原始枚举值和对应的字符串名称 */printf("状态值: %d, 名称: %s\n",s,my_state_name[s]);/* 显示带"end"后缀的字符串 */printf("状态值: %d, 后缀名称: %s\n",s,my_state_name_end[s]);/* 显示加1后的整数和对应名称 */printf("加1值: %d, 对应状态: %s\n",my_state_add[s],my_state_name[s]);/* 显示加1后的整数和带后缀的名称 */printf("加1值: %d, 后缀名称: %s\n",my_state_add[s],my_state_name_end[s]);printf("------------------------------\n");/* 分隔线,提高可读性 */}printf("\nX-Macro 技术优势总结:\n");printf("1. 只需在 FOREACH_STATE 中添加新状态,所有数组自动扩展\n");printf("2. 枚举值、字符串、派生数据保持同步\n");printf("3. 减少手动维护错误\n");printf("4. 代码更加简洁和一致\n");return0;}

用在哪?

  1. 状态机 (State Machines)
    如代码中的例子,在 USB-PD、蓝牙协议栈或 TCP/IP 协议中,状态非常多。
  • 用途:同步定义状态枚举、状态转换日志(字符串)、以及状态处理函数的跳转表。
  • 痛点:如果你手动维护,增加一个STATE_RECOVERY状态时,很容易在switch-case里漏掉它,导致程序跑飞。
  1. 错误码与告警系统 (Error Codes)
    在复杂的系统中,通常有几百个错误码。
  • 用途
    • 生成枚举:ERR_TIMEOUT,ERR_OUT_OF_MEMORY
    • 生成描述:"System timeout","Memory allocation failed"
  • 优势:你可以一键生成一个 `const char* error_to_tring(int code) 函数,永远不会出错。
  1. 硬件寄存器与引脚配置 (Hardware IO/Registers)
    在嵌入式开发(如 STM32 或 Linux 驱动)中,你需要配置大量的 GPIO 引脚。
  • 用途
    #define GPIO_LIST(X) \ X(GPIOA, 5, "LED_RED") \ X(GPIOB, 12, "LCD_CS") \ X(GPIOC, 13, "BUTTON")
  • 优势:通过这份名单,你可以一次性生成:
    1. 引脚初始化的代码。
    2. 定义引脚索引的枚举。
    3. 调试时的引脚名称查询表。
  1. 命令行解析与菜单系统 (CLI / Shell)
    如果你在做串口控制台(如同路由器或交换机的命令行)。
  • 用途
    • 生成命令名列表。
    • 生成对应的帮助信息(Help Message)。
    • 生成对应的回调函数(Callback Functions)。
  • 优势:增加一个新命令只需在列表里加一行,对应的帮助信息和函数关联就自动生成了。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:44:30

远程办公,设备为何总失控?

当半数员工散落在不同城市&#xff0c;甚至不同时区&#xff0c;IT部门的噩梦便开始了&#xff1a;新同事的笔记本电脑迟迟无法完成安全配置&#xff1b;销售人员的平板电脑莫名无法访问内部系统&#xff1b;设计团队的Mac设备始终未安装关键更新……这并非个别现象&#xff0c…

作者头像 李华
网站建设 2026/4/16 4:07:12

【低成本上岸指南 | 低成本、快速度的普刊推荐】硕士/博士毕业 | 本科保研/奖学金加分 | 高职/中职教师评讲师 | 基层医护人员、工程师评初级/中级职称 | 课题/项目结题 | 权威适配+极速录用

“核心太难&#xff1f;普刊来凑&#xff01;”——面对核心期刊发表难的问题&#xff0c;普刊成为多类人群的实用选择。刚需≠低端&#xff1a;普刊“真香”现场——本硕博生、教师医生、工程师都在用的速效发表通道硕士/博士“放水”毕业学校规定“公开发表论文即可”&#x…

作者头像 李华
网站建设 2026/4/11 16:35:00

复习党有救啦!这蓝牙耳机降噪太顶了!

期末复习周的宿舍&#xff0c;真的没法待了。上铺追剧外放&#xff0c;对面室友开黑连麦&#xff0c;我对着错题本发呆半小时&#xff0c;一个字都没看进去。后来听朋友建议&#xff0c;买了华为的FreeBuds 7i&#xff0c;试了一下降噪模式&#xff0c;周围的吵闹声一下子就弱了…

作者头像 李华
网站建设 2026/4/16 7:32:13

解锁手机大屏体验:QtScrcpy跨平台投屏完全指南

解锁手机大屏体验&#xff1a;QtScrcpy跨平台投屏完全指南 【免费下载链接】QtScrcpy Android实时投屏软件&#xff0c;此应用程序提供USB(或通过TCP/IP)连接的Android设备的显示和控制。它不需要任何root访问权限 项目地址: https://gitcode.com/barry-ran/QtScrcpy 想…

作者头像 李华
网站建设 2026/4/14 0:15:38

VB实现excel的层级折叠

​ 主要记录一下使用入栈&出栈的方式&#xff0c;记录下excel的内容折叠公式&#xff0c;代码的实现不重要。重要的是解决问题的思路 这个算法中创建分组的时机是&#xff1a;当需要闭合一个分组时&#xff0c;且该分组包含多行内容。 具体触发条件 1. 基本规则 创建分组发…

作者头像 李华