指定初始化器代码长度可变的结构体数组初始化

问题引入

在工程中结构体数组是一个经常用到的数据结构。数组的长度有时候我们需要用宏定义控制,方便我们在做系列产品的时候随时修改。

数组长度容易控制,直接修改长度宏定义即可。

然而,如果我们在定义结构体的时候使用初始化器做了初始化,初始化器的代码并没有做可伸缩处理,初始化器代码比宏长的时候就会出问题

#define MAX_PORT 1
struct s_port_t port[MAX_PORT] =
{
    [0]{
       .len = 1,
       .data = 0xffed,
       .holder = 2,
    },
    [1]{
       .len = 1,
       .data = 0xffed,
       .holder = 2,
    },
};

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.c|43|error: array index in initializer exceeds array bounds
Build failed: 1 error(s), 1 warning(s) (0 minute(s), 0 second(s))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

本文就是为了解决初始化器无法伸缩的问题。

解决办法

先放解决方法,跑一下,下一节分析

#define __CONNECT1__(...)   [0]__VA_ARGS__
#define __CONNECT2__(...)   [1]__VA_ARGS__,__CONNECT1__(__VA_ARGS__)
#define __CONNECT3__(...)   [2]__VA_ARGS__,__CONNECT2__(__VA_ARGS__)
#define __CONNECT4__(...)   [3]__VA_ARGS__,__CONNECT3__(__VA_ARGS__)
#define __CONNECT5__(...)   [4]__VA_ARGS__,__CONNECT4__(__VA_ARGS__)
#define __CONNECT6__(...)   [5]__VA_ARGS__,__CONNECT5__(__VA_ARGS__)
#define __CONNECT7__(...)   [6]__VA_ARGS__,__CONNECT6__(__VA_ARGS__)
#define __CONNECT8__(...)   [7]__VA_ARGS__,__CONNECT7__(__VA_ARGS__) 
/* #define __CONNECT9__...... 续写以支持更多 */                   
#define __STRUCT_BUNTCH_INIT(__NUM, ...)    {__CONNECT##__NUM##__(__VA_ARGS__)}     
 //套一层,让__NUM先展开为数字           
#define STRUCT_BUNTCH_INIT(__NUM, ...)      __STRUCT_BUNTCH_INIT(__NUM, __VA_ARGS__)

上面最终创建了STRUCT_BUNTCH_INIT(__NUM, …) 宏,此宏定义第一个参数是要展开的结构体成员长度,后面的…是一个结构体成员的初始化代码。STRUCT_BUNTCH_INIT(__NUM, …) 宏最终会在调用位置展开为__NUM数量的相同的初始化代码。下面是调用示例

struct s_port_t{    //port 结构体
    uint8_t len;
    uint16_t data;
    uint16_t holder;
};
#define MAX_PORT   2
struct s_port_t port[MAX_PORT] = STRUCT_BUNTCH_INIT(
   MAX_PORT,       /*  结构体参数个数          */
   {               /*  每个结构体的初始化代码  */
       .len = 1,
       .data = 0xffed,
       .holder = 2,
   }
);

上面将会被展开为如下

//MAX_PORT定义为2:
{
    [1]{ .len = 1, .data = 0xffed, .holder = 2, },
    [0]{ .len = 1, .data = 0xffed, .holder = 2, }
}

//MAX_PORT定义为3:
{
    [2]{ .len = 1, .data = 0xffed, .holder = 2, },
    [1]{ .len = 1, .data = 0xffed, .holder = 2, },
    [0]{ .len = 1, .data = 0xffed, .holder = 2, }
}

如此,我们便实现了初始化器代码长度可变的目的

宏定义分析

调用__CONNECT1__返回如下

__CONNECT1__(...)   [0]__VA_ARGS__

调用__CONNECT2__返回如下

__CONNECT2__(...)   [1]__VA_ARGS__,__CONNECT1__(__VA_ARGS__)
展开
__CONNECT2__(...)   [1]__VA_ARGS__,[0]__VA_ARGS__

以此类推,调用__CONNECT3____返回如下

__CONNECT3__(...)   [2]__VA_ARGS__,[1]__VA_ARGS__,[0]__VA_ARGS__

__STRUCT_BUNTCH_INIT决定调用哪一个CONNECT宏,这里使用到了##粘接宏,用处如下

#define __STRUCT_BUNTCH_INIT(__NUM, ...)    {__CONNECT##__NUM##__(__VA_ARGS__)} 

__STRUCT_BUNTCH_INIT(1, ...)
展开为
{__CONNECT1__(__VA_ARGS__)} 

__STRUCT_BUNTCH_INIT(8, ...)
展开为
{__CONNECT8__(__VA_ARGS__)} 

而我们传入_NUM的一般不是数字而是宏定义如MAX_PORT ,我们需要在__STRUCT_BUNTCH_INIT外面套一层STRUCT_BUNTCH_INIT,否则将会被展开为

{__CONNECTMAX_PORT__(__VA_ARGS__)} 

最后, […]参数会被传递到__VA_ARGS__中
全部展开,得到如下

 __STRUCT_BUNTCH_INIT(3, ...) 
 展开
 {__CONNECT3__(...)}
 展开
{
	[2]__VA_ARGS__,
	[1]__VA_ARGS__,
	[0]__VA_ARGS__,
}

结束

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菠萝地亚狂想曲

送我一瓶农夫山泉?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值