news 2026/9/7 0:49:27

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/9/6 9:22:41

Gitee:本土化项目管理软件的崛起与未来

Gitee&#xff1a;本土化项目管理软件的崛起与未来 从代码托管到智能开发中枢的演进之路 在数字化转型的浪潮席卷全球的当下&#xff0c;项目管理软件已成为企业提升运营效率的关键抓手。作为中国本土领先的代码托管与协作平台&#xff0c;Gitee&#xff08;码云&#xff09;…

作者头像 李华
网站建设 2026/9/6 12:19:22

Claude Code界面美化:3个步骤让你的AI助手颜值飙升

Claude Code界面美化&#xff1a;3个步骤让你的AI助手颜值飙升 【免费下载链接】claude-code Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex co…

作者头像 李华
网站建设 2026/9/7 0:32:28

用R分析时间序列(time series)数据

时间序列&#xff08;time series&#xff09;是一系列有序的数据。通常是等时间间隔的采样数据。如果不是等间隔&#xff0c;则一般会标注每个数据点的时间刻度。 下面以time series 普遍使用的数据 airline passenger为例。 这是十一年的每月乘客数量&#xff0c;单位是千人次…

作者头像 李华
网站建设 2026/9/6 4:26:15

水利工程前沿国际期刊精选

期刊名称: 当代水电科技ISSN印刷版: 3060-8767研究领域: 工程技术 水利工程 电力能源 出版模式: 开放获取&#xff08;OA&#xff09;出版周期: 2-3个月出刊检索版面要求: 5000字符/3版期刊收录: 知网CNKI 出版社: 新加坡✥聚知刊期刊名称: 水电水利ISSN印刷版: 2529-782…

作者头像 李华
网站建设 2026/9/6 3:47:59

25 万亿美元超级风口下,中国智造如何执掌机器人时代

当摩根士丹利在《机器人年鉴》中抛出 “2050 年全球机器人硬件销售额将达 25 万亿美元” 的预测时&#xff0c;一个足以重塑全球产业格局的超级风口已然成型。从 2025 年的约 1000 亿美元到 25 万亿美元的指数级跨越&#xff0c;不仅意味着机器人将从工业车间、物流仓库走向千家…

作者头像 李华