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的作者是很厉害的。