Lwip中结构体与无条件花括号的奇妙组合

Lwip中结构体与无条件花括号的奇妙组合

Lwip的源码很多人都分析过,大部分的分析都提及了“memp_std.h”这个有意思的 文件,它是通过##连接符的方式,来简化程序编写,使程序变得优美简短。比如说,“memp.h”里面有这样一个代码段

typedef enum {
#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_##name,
#include "lwip/priv/memp_std.h"
  MEMP_MAX
} memp_t;

是不是看起来,有点懵逼,没关系,看看memp_std.h这个文件是个什么鬼

#if LWIP_RAW
LWIP_MEMPOOL(RAW_PCB,        MEMP_NUM_RAW_PCB,         sizeof(struct raw_pcb),        "RAW_PCB")
#endif /* LWIP_RAW */

#if LWIP_UDP
LWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        "UDP_PCB")
#endif /* LWIP_UDP */

#if LWIP_TCP
LWIP_MEMPOOL(TCP_PCB,        MEMP_NUM_TCP_PCB,         sizeof(struct tcp_pcb),        "TCP_PCB")
LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN,  sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")
LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        "TCP_SEG")
#endif /* LWIP_TCP */

#if LWIP_ALTCP && LWIP_TCP
LWIP_MEMPOOL(ALTCP_PCB,      MEMP_NUM_ALTCP_PCB,       sizeof(struct altcp_pcb),      "ALTCP_PCB")
#endif /* LWIP_ALTCP && LWIP_TCP */

#if LWIP_IPV4 && IP_REASSEMBLY
LWIP_MEMPOOL(REASSDATA,      MEMP_NUM_REASSDATA,       sizeof(struct ip_reassdata),   "REASSDATA")
#endif /* LWIP_IPV4 && IP_REASSEMBLY */
#if (IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF) || (LWIP_IPV6 && LWIP_IPV6_FRAG)
LWIP_MEMPOOL(FRAG_PBUF,      MEMP_NUM_FRAG_PBUF,       sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
#endif /* IP_FRAG && !LWIP_NETIF_TX_SINGLE_PBUF || (LWIP_IPV6 && LWIP_IPV6_FRAG) */

#if LWIP_NETCONN || LWIP_SOCKET
LWIP_MEMPOOL(NETBUF,         MEMP_NUM_NETBUF,          sizeof(struct netbuf),         "NETBUF")
LWIP_MEMPOOL(NETCONN,        MEMP_NUM_NETCONN,         sizeof(struct netconn),        "NETCONN")
#endif /* LWIP_NETCONN || LWIP_SOCKET */

#if NO_SYS==0
LWIP_MEMPOOL(TCPIP_MSG_API,  MEMP_NUM_TCPIP_MSG_API,   sizeof(struct tcpip_msg),      "TCPIP_MSG_API")

看懂了吗?## 是 C语言得连接符,用于连接不同得token,上面的代码段,在预编译完成后,应该是这样的:

1 typedef enum
2 {
3 MEMP_RAW_PCB,
4 MEMP_UDP_PCB,
5 MEMP_TCP_PCB,
6 MEMP_TCP_PCB_LISTEN,
7 MEMP_TCP_SEG,
8 MEMP_ALTCP_PCB,
9 MEMP_REASSDATA,
10 MEMP_NETBUF,
11 MEMP_NETCONN,
12 MEMP_MAX
13 } memp_t;

用这样得方式,按照这种包含头文件的原理,只需要定义 LWIP_MEMPOOL 宏的作用, 就能产生很多
与内存池相关的操作, 如在 memp.c 文件的开头还定义了如下代码:

1 #define LWIP_MEMPOOL(name,num,size,desc) \          //将LWIP_MEMPOOL宏定义为LWIP_MEMPOOL_DECLARE 
2 LWIP_MEMPOOL_DECLARE(name,num,size,desc)            //这两句在“memp.c”文件首部
3
 // 这一段在“memp.h”文件中,定义了LWIP_MEMPOOL_DECLARE 函数
  #define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \
4 #define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) \
5 u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)]
6
7 LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1U))
8
9 #define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \
10 LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, \
11 ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \
12 \
13 LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \
14 \
15 static struct memp *memp_tab_ ## name; \
16 \
17 const struct memp_desc memp_ ## name = { \
18 DECLARE_LWIP_MEMPOOL_DESC(desc) \
19 LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \
20 LWIP_MEM_ALIGN_SIZE(size), \
21 (num), \
22 memp_memory_ ## name ## _base, \
23 &memp_tab_ ## name \
24 };

有趣的点在哪里呢,在最后一个结构体

const struct memp_desc memp_ ## name = { \
18 DECLARE_LWIP_MEMPOOL_DESC(desc) \
19 LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \
20 LWIP_MEM_ALIGN_SIZE(size), \
21 (num), \
22 memp_memory_ ## name ## _base, \
23 &memp_tab_ ## name \
24 };

memp_desc这个结构体定义是这样的

struct memp_desc {
#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY
  /** Textual description */
  const char *desc;
#endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY */
#if MEMP_STATS
  /** Statistics */
  struct stats_mem *stats;
#endif

  /** Element size */
  u16_t size;

#if !MEMP_MEM_MALLOC
  /** Number of elements */
  u16_t num;

  /** Base address */
  u8_t *base;

  /** First free element of each pool. Elements form a linked list. */
  struct memp **tab;
#endif /* MEMP_MEM_MALLOC */
};

memp_desc是一个结构体,可是为什么内部成员之间用的是逗号而不是分号?? 这个 = 号是什么鬼?
我自己写了个小程序测试了下,其实是可以这样用的。

struct memp_desc {
int a;
int b;
const char* c;
};

struct memp_desc memp = {   //此处将结构赋值为一个未命名的数组 
	2,
	3,
	"Hello!"
};



main()
{

	printf("%s\n",memp.c);
	
}

输出的结果是“Hello!”。

所以,其实它是用了一个无条件花括号把结构体内的成员赋值,然后再把这个花括号值符给结构体。我查了下书,没有找到关于无条件花括号的相关信息。不知道这样用依据的规则是什么,希望有大佬可以解答一下。

接下来的问题是,为啥要这样用?很简单,因为它是在程序外给结构体成员部分问赋值的,如果不这样写,就得这样写

const struct memp_desc memp_ ## name { \
    const char *desc = DECLARE_LWIP_MEMPOOL_DESC(desc); \
    struct stats_mem *stats = LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name); \
    u16_t size = LWIP_MEM_ALIGN_SIZE(size);\
    u16_t num = (num); \
    u8_t *base = memp_memory_ ## name ## _base;\
    struct memp **tab = &memp_tab_ ## name \
  };

这有两个问题,一个是,宏允许这样操作吗?第二个是,这样明显不是上面的简练优雅。
不得不说,Lwip的作者是很厉害的。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值