出神入化的枚举结构体函数声明

瞻仰完大神改STM32中断向量表的代码,今天我们来看看“大神”写的枚举、结构、函数声明,还是一样的配方,一样的烧脑。

少废话,先放代码。第一段是枚举,第二段是函数,第三段是对一个数组的初始化。

//==============================================================================
#define UTIL_EVENT_Define(T,X)    
#define UTIL_STATE_Define(T,X)    UTIL_STATE_ENUM(T,X),    
enum
{
#include "APP_PROC_STATE_M_NET_SETUP_define.h"
};
#undef UTIL_STATE_Define  
#undef UTIL_EVENT_Define
//==============================================================================

//==============================================================================
#define UTIL_STATE_Define(T,X)    UTIL_STATE_FUNC_Extern(T,X) 
#define UTIL_EVENT_Define(T,X)
#include "APP_PROC_STATE_M_NET_SETUP_define.h"
#undef UTIL_STATE_Define 
#undef UTIL_EVENT_Define
//==============================================================================

//==============================================================================
#define UTIL_STATE_Define(T,X)    UTIL_STATE_FUNC_ITEM_IN_TAB(T,X),
#define UTIL_EVENT_Define(T,X)
const __pgm __state_func_t APP_PROC_STATE_M_NET_SETUP_TAB[]=
{
#include "APP_PROC_STATE_M_NET_SETUP_define.h"
};
#undef UTIL_STATE_Define 
#undef UTIL_EVENT_Define

这个APP_PROC_STATE_M_NET_SETUP_define.h 头文件内容比较多,但是每一项都大同小异,我这里放一部分出来。

UTIL_STATE_Define(APP_PROC_STATE_M_NET_SETUP_t,BEGIN)
UTIL_STATE_Define(APP_PROC_STATE_M_NET_SETUP_t,END)
UTIL_STATE_Define(APP_PROC_STATE_M_NET_SETUP_t,AT_E0)

UTIL_STATE_Define(APP_PROC_STATE_M_NET_SETUP_t,AT_CPIN)

不知道各位看官在第一次阅读这个代码的时候,有没有立马理解里面的门道。能写出这样代码的人,对编译器的理解,C语言的功力都是深厚的,不然也不能被叫做大神。接下来我就来好好理解理解里面的门道。

首先是对#include的理解。平时我们都知道要获取一个模块对外的函数声明,结构体枚举定义,变量声明等,要include那个模块的头文件。这只是会用,其实include的本质,是将指定头文件的内容替换掉#include这句,当然这个操作是编译器去执行的。

举个例子

//ModuleA.h

extern uint8_t Test;
uint8_t GetFun(void);
//ModuleB.c


#include "ModuleA.h"


....
....
....

我们在模块B的c文件中包含了模块A的头文件。编译器在编译的时候,首先会把模块B的c文件变成这样,然后才进行编译。

//ModuleB.c

extern uint8_t Test;
uint8_t GetFun(void);



...
...
...

宏定义的本质跟#include是一样的,编译器在编译之前,会把代码里的宏替换成定义的内容。

理解了这些,我们拿一开始那段代码里的枚举定义来看看

#define UTIL_EVENT_Define(T,X)    
#define UTIL_STATE_Define(T,X)    UTIL_STATE_ENUM(T,X),    
enum
{
#include "APP_PROC_STATE_M_NET_SETUP_define.h"
};
#undef UTIL_STATE_Define  
#undef UTIL_EVENT_Define

也就是说,编译器编译的时候会把APP_PROC_STATE_M_NET_SETUP_define.h文件里的内容“粘贴”到枚举定义里,我们试着还原一下“粘贴”后的效果

#define UTIL_EVENT_Define(T,X)    
#define UTIL_STATE_Define(T,X)    UTIL_STATE_ENUM(T,X),    
enum
{
UTIL_STATE_Define(APP_PROC_STATE_M_NET_SETUP_t,BEGIN)
UTIL_STATE_Define(APP_PROC_STATE_M_NET_SETUP_t,END)
UTIL_STATE_Define(APP_PROC_STATE_M_NET_SETUP_t,AT_E0)

UTIL_STATE_Define(APP_PROC_STATE_M_NET_SETUP_t,AT_CPIN)
};
#undef UTIL_STATE_Define  
#undef UTIL_EVENT_Define

这个时候留意一下,枚举定义之前,对UTIL_STATE_Define这个宏进行定义,实际情况应该是这样

enum
{
UTIL_STATE_ENUM(APP_PROC_STATE_M_NET_SETUP_t,BEGIN),
UTIL_STATE_ENUM(APP_PROC_STATE_M_NET_SETUP_t,END),
UTIL_STATE_ENUM(APP_PROC_STATE_M_NET_SETUP_t,AT_E0),

UTIL_STATE_ENUM(APP_PROC_STATE_M_NET_SETUP_t,AT_CPIN),
};

那这个UTIL_STATE_ENUM宏又是啥定义,我在另外一个头文件里找到了。

#define UTIL_STATE_ENUM(T,X)              STATE_ENUM_##T##_##X

好了,那么枚举的终极展开就是这样,名字真的。。。哎,好长,好长。

enum
{
STATE_ENUM_APP_PROC_STATE_M_NET_SETUP_t_BEGIN,
STATE_ENUM_APP_PROC_STATE_M_NET_SETUP_t_END,
STATE_ENUM_APP_PROC_STATE_M_NET_SETUP_t_AT_E0,
STATE_ENUM_APP_PROC_STATE_M_NET_SETUP_t_AT_CPIN,
};

这份代码接下来还有个地方有意思,就是刚刚这个APP_PROC_STATE_M_NET_SETUP_define.h文件不仅仅被用在了枚举定义里,还被用在函数声明和数组初始化里。这是怎么做到的呢。

我们来看一下,函数声明部分。

#define UTIL_STATE_Define(T,X)    UTIL_STATE_FUNC_Extern(T,X) 
#define UTIL_EVENT_Define(T,X)
#include "APP_PROC_STATE_M_NET_SETUP_define.h"
#undef UTIL_STATE_Define 
#undef UTIL_EVENT_Define

真鸡贼,在函数定义之前,把UTIL_STATE_Define这个宏重新定义了,这个宏就是头文件里的那个。UTIL_STATE_FUNC_Extern这个宏的定义如下。

#define UTIL_STATE_FUNC(T,X)              STATE_FUNC_##T##_##X
#define UTIL_STATE_FUNC_INLINE(T,X)       STATE_FUNC_##T##_##X##_
#define UTIL_STATE_FUNC_Extern(T,X)       void UTIL_STATE_FUNC(T,X)(UTIL_EVENT_STATE_t *p_es);

又是各种拼接宏,看得头晕,我就不展开了,总之他通过这种方法,定义了一堆的函数,并且函数的名字靠编译器编译的时候去拼接。更鸡贼的是,他在函数定义之后,还#undef了之前定的宏,防止后面用错。

最后,我们来看一下数组的初始化。

#define UTIL_STATE_Define(T,X)    UTIL_STATE_FUNC_ITEM_IN_TAB(T,X),
#define UTIL_EVENT_Define(T,X)
const __pgm __state_func_t APP_PROC_STATE_M_NET_SETUP_TAB[]=
{
#include "APP_PROC_STATE_M_NET_SETUP_define.h"
};
#undef UTIL_STATE_Define 
#undef UTIL_EVENT_Define

还是一样的手法,我们只有看了UTIL_STATE_FUNC_ITEM_IN_TAB这个宏,才知道数组是怎么初始化的。

#define UTIL_STATE_FUNC_ITEM_IN_TAB(T,X)  [UTIL_STATE_ENUM(T,X)]=UTIL_STATE_FUNC(T,X)

这里用到了之前枚举和函数定义的拼接宏。枚举,函数声明,数组初始化,合起来总的想法就是,定义一个函数指针数组,用枚举做索引,把函数名字写到数组的初始化。

确实,通过这一顿操作,少写了很多代码,这些代码都靠编译器自己完成了。但是可读性嘛,谁看谁知道。

看到这里,可能大家跟我有一样的疑问,这么花式地把枚举,函数给定义了,用的时候咋办咧。无他,还是靠拼接宏。比如要用到枚举,只能是这样

UTIL_STATE_ENUM(APP_PROC_STATE_M_NET_SETUP_t,BEGIN)

这样的代码,首先可读性十分差劲,滥用拼接宏,会频繁打断阅读的思路,最可恶的是函数的名字用拼接,在调试的时候往往无法直接跳转到定义,想要搜索也无从下手,效率低下。函数名字用拼接还有一个十分恶劣的影响,就是编译出错的时候,错误信息里函数的名字是编译器对宏进行完全展开后的名字,你看到函数的名字会非常的陌生和懵逼,肯定无法第一时间就想起来是哪个函数。这样的代码,也就适合拿来提升你对编译器和C语言的理解了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值