在项目中有时会遇到这样的情况:枚举信息需要关联相关的信息。

比如,定义一系列的故障类型 , 为了便于故障进行日志输出 , 一般会定义一个与之关联的字符串数组。

 typedef enum{PARAM_ERR,PARSER_ERR,TIMEOUT_ERR,NOTEXIT_ERR,...}SYS_ERR_t;​const char* ERR_INFO[]={"param error","parser error","timeout error","not exit error"};#define ERR_STR(x)   ERR_INFO[x]​void test(void){printf(ERR_STR(PARAM_ERR));printf(ERR_STR(NOTEXIT_ERR));}

目前这种定义方法 ,枚举和字符串需要同时修改 ,有可能造成只增加枚举而导致数组越界

使用X宏

 #define  ERR_T     \X(PARAM_ERR , "param error")\X(PARSER_ERR , "parser error")\X(TIMEOUT_ERR , "timeout error")\X(NOTEXIT_ERR , "not exit error")​#define X(a , b)     a,typedef enum{ERR_T}SYS_ERR_t;#undef  X​#define X(a , b)  b,const char* ERR_INFO[]={ERR_T};

使用X宏最终只需要 修改 ERR_T 即可 ,减少出错的可能性 ,至于为啥叫X 宏 , 没有找到相关说明,本质是使用了#undef 对 X进行了取消定义,进行重定义 , 导致 枚举 和数组 使用相同的 ERR_T 但 表示的内容不同 ,这里很好的说明了预处理阶段 只是 一个替换过程 ,程序 预处理完成后 ,所有的宏都不将存在,而是替换成了对应的文本。

另一个实用的例子 :

定义一种数据帧格式 , 功能码 加有效字段 ,不同功能码长度不同 ,附带不同信息

typedef struct{uint8_t cmd;uint8_t len;const char* info}p_cmd_t;​enum{LAP_CMDUL_CFRM          = 0x00,LAP_CMDUL_PPAT          = 0x02,LAP_CMDUL_TEMP          = 0x10,LAP_CMDUL_ALERT         = 0x0F,LAP_CMDUL_TOTAL_FLOW    = 0x71,LAP_CMDUL_RATE_FLOW     = 0x72,LAP_CMDUL_REVERSE_FLOW  = 0x73,LAP_CMDUL_FROZEN_FLOW   = 0x74,LAP_CMDUL_VER           = 0x90,LAP_CMDUL_TIMEUL        = 0x98,};​p_cmd_t  cmd_tab[]={{LAP_CMDUL_CFRM          ,  1 ,  "LAP_CMDUL_CFRM"        }, {LAP_CMDUL_PPAT          ,  2 ,  "LAP_CMDUL_PPAT"        },{LAP_CMDUL_TEMP          ,  3 ,  "LAP_CMDUL_TEMP"        },{LAP_CMDUL_ALERT         ,  4 ,  "LAP_CMDUL_ALERT"       },{LAP_CMDUL_TOTAL_FLOW    ,  5 ,  "LAP_CMDUL_TOTAL_FLOW"  },{LAP_CMDUL_RATE_FLOW     ,  6 ,  "LAP_CMDUL_RATE_FLOW"   },{LAP_CMDUL_REVERSE_FLOW  ,  7 ,  "LAP_CMDUL_REVERSE_FLOW"},{LAP_CMDUL_FROZEN_FLOW   ,  8 ,  "LAP_CMDUL_FROZEN_FLOW" },{LAP_CMDUL_VER           ,  9 ,  "LAP_CMDUL_VER"         }, {LAP_CMDUL_TIMEUL        ,  9 ,  "LAP_CMDUL_TIMEUL"      },};

X宏的实现方法

#define   CMD_LIST   \X(LAP_CMDUL_CFRM        , 0x00  , 1  , "LAP_CMDUL_CFRM")\X(LAP_CMDUL_PPAT        , 0x02  , 2  , "LAP_CMDUL_PPAT")\X(LAP_CMDUL_TEMP        , 0x10  , 3  , "LAP_CMDUL_TEMP")\X(LAP_CMDUL_ALERT       , 0x0F  , 4  , "LAP_CMDUL_ALERT")\X(LAP_CMDUL_TOTAL_FLOW  , 0x71  , 5  , "LAP_CMDUL_TOTAL_FLOW")\X(LAP_CMDUL_REVERSE_FLOW, 0x72  , 6  , "LAP_CMDUL_REVERSE_FLOW")\X(LAP_CMDUL_FROZEN_FLOW , 0x73  , 7  , "LAP_CMDUL_FROZEN_FLOW")\X(LAP_CMDUL_VER         , 0x90  , 8  , "LAP_CMDUL_VER")\X(LAP_CMDUL_TIMEUL      , 0x98  , 9  , "LAP_CMDUL_TIMEUL")\​/*以下内容无需再修改*/#define X(a ,b , c ,d)     a = b,enum{CMD_LIST};#undef X​#define  X(a , b ,c ,d)   {b,c,d},p_cmd_t  cmd_tab[]= {CMD_LIST};#undef X

总体来看 ,只是将分散的修改集中到了一起 ,修改的时候方便,不会出错。而且可以将CMD_LIST 任意成员进行关联 ,只需要重定义X 即可。可能两个事务的关联还难以体现X宏的 作用 , 当多个定义都有关联时 , 修改一个需要同步修改其他的 , 这个时候才能体现X宏的作用。

【c语言】:X宏的应用相关推荐

  1. 如何用C语言改变宏定义的大小,C语言中宏定义使用的小细节

    C语言中宏定义使用的小细节 #pragma#pragma 预处理指令详解 在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#p ...

  2. c 语言程序设计阚道宏,C语言用宏实现静态多态

    综述 多态性是面向对象程序设计的一个重要特征. 在C++语言中,多态指的是:具有不同功能的函数可以用同一个函数名,可以用一个函数名调用不同内容的函数. C++的多态分为两种: 1. 静态多态性(编译时 ...

  3. C语言 va_arg 宏 - C语言零基础入门教程

    目录 一.前言 二.va_arg 简介 三.va_arg 使用 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.前言 对 printf ...

  4. C语言 va_end 宏 - C语言零基础入门教程

    目录 一.前言 二.va_end 简介 三.va_end 使用 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.前言 对 printf ...

  5. C语言 va_start 宏 - C语言零基础入门教程

    目录 一.前言 二.va_start 简介 三.va_start 使用 四.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.前言 对 pr ...

  6. c语言用宏定义常量_使用宏定义常量以在C的数组声明中使用

    c语言用宏定义常量 As we know that, while declaring an array we need to pass maximum number of elements, for ...

  7. C/C++编程笔记:浅析 C 语言中宏定义的使用,知识点全解

    宏定义是用一个标识符来表示一个字符串,在宏调用中将用该字符串代替宏名.给程序员提供了便利,使程序更加清晰,便于阅读和理解,进一步提高了程序的运行效率,对于嵌入式系统而言,为了能达到性能要求,宏是一种很 ...

  8. 【C语言】----宏定义,预处理宏

    什么是宏? 宏是学习任何语言所不可缺少的,优秀的宏定义可以使得代码变得很简洁且高效,有效地提高编程效率. 宏是一种预处理指令,它提供了一种机制,可以用来替换源代码中的字符串,解释器或编译器在遇到宏时会 ...

  9. c语言中宏定义的字符替换#define M(x,y,z) x*y+z

    C语言中宏定义的字符替换问题 例子: 在c语言中定义如下宏 #define M(x,y,z) x*y+z 给定如下程序 #include<stdio.h> #include<stdl ...

  10. C语言-入门-宏定义(十七)

    预处理 编译一个C语言程序的第一步骤就是预处理阶段,这一阶段就是宏发挥作用的阶段.C预处理器在源代码编译之前对其进行一些文本性质的操作,主要任务包括删除注释.插入被#include进来的文件内容.定义 ...

最新文章

  1. Zookeeper源码分析:Follower角色初始化
  2. 用Eclipse 开发Dynamic Web Project应用程序
  3. leetcode 3.无重复字符的最长子串(中等)
  4. rosdep init和rosdep update出错处理
  5. 安卓开源项目周报1220
  6. 靶场练习第十天~vulnhub靶场之dc-2
  7. [WCF]NetTcpBinding在IIS中使用的详细配置方法
  8. ES6_let和const_note
  9. 图片随鼠标滚动而任意浮动
  10. 蓝桥杯2019年第十届C/C++省赛C组第四题-质数
  11. 微信支付开发(1) JS API支付V3版(转)
  12. PTA平台之温度转换
  13. SQLyog中文版安装教程
  14. 图的深度优先遍历和广度优先遍历
  15. 深度学习的权重衰减是什么_深度学习-权重衰减
  16. c++ encode 函数_encode 在C++中的用法
  17. Watching the English:英国社会阶层攀爬指南?
  18. c语言中calloc是什么意思,C语言中malloc和calloc以及relloc函数的区别
  19. 解决序列长期依赖的法宝——注意力机制
  20. 权力的游戏——读《原则2 :应对变化中的世界秩序》(中)

热门文章

  1. web服务器的配置与简单动态网页设计实验,WEB服务器配置实验.ppt
  2. [游泳] 5 tips for Beginner freestylers
  3. GPIO驱动写错,导致内存出现问题,系统死掉
  4. 培训Python后推荐就业-吃香行业
  5. Transform角度和旋转
  6. php 微信支付 传参数,php,微信支付_微信支付 传递自定义参数,php,微信支付,微信开发 - phpStudy...
  7. 【SigmaGrid控件】使用 demo
  8. 猎头顾问那些年,那些奇葩候选人——北漂18年(58)
  9. soho 一族(2)
  10. 项目工作任务管理刍议