LWIP中一个奇怪宏定义的解析

本文详细解析了lwIP中内存池的定义方式及其大小计算方法,对比了不同版本中的实现差异,并介绍了宏定义在此过程中的巧妙应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于lwip中内存池的大小,不同的lwip版本定义的方式不一样,但都大同小异。

在lwip_1.4.1中,通过一个static函数获取内存池大小:

u32_t memp_get_memorysize(void)
{
  u32_t length=0;
    length=(
         MEM_ALIGNMENT-1
         #define LWIP_MEMPOOL(name,num,size,desc) + ((num)*(MEMP_SIZE+MEMP_ALIGN_SIZE(size)))
         #include \"lwip/memp_std.h\"
      );
    return length;
}

在lwip_2.0中,内存池的大小为:

static u8_t memp_memory [ MEM_ALIGNMENT - 1
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/memp_std.h"
];

这两段代码存在于lwip的memp.c中。看到这个memp_memory数组,是不是在怀疑自己的眼睛?这到底是不是一个数组呢?定义的数组里竟然还有两个关键字(include和define)?作者这是在干嘛呢?

不过在整理脉络之后,你不得不佩服lwip作者写代码的能力。现在我们就来尝试理解一下这个memp_memory数组。

LWIP_MEMPOOL宏是在数组中定义的,那么在数组中定义的宏和在全局定义的宏有什么不同呢?是作用域不同还是有其他什么差别?

其实,宏定义的作用域是同文件内从定义开始起作用,直到取消定义(undef)为止。那么mem_memroy数组等价于:

#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
static u8_t memp_memory [ MEM_ALIGNMENT - 1
#include "lwip/memp_std.h"
];

这里的 LWIP_MEMPOOL(name,num,size,desc) 定义成了 + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )

include关键字其实就是把lwip/memp_std.h包含进数组。我们来看看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 */

#undef LWIP_MEMPOOL

我们将这段代码用include包含到 memp_memory 数组中,即:

#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
static u8_t memp_memory [ MEM_ALIGNMENT - 1
+ (LWIP_MEMPOOL(RAW_PCB,        MEMP_NUM_RAW_PCB,         sizeof(struct raw_pcb),        "RAW_PCB"))
+ (LWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        "UDP_PCB"))
+ ...
];
#undef LWIP_MEMPOOL

这样就能清晰的看到memp_memory数组的大小了。在mem_memory数组之前用define定义了LWIP_MEMPOOL,在memp_memory数组定义后,用undef取消了LWIP_MEMPOOL的定义。

同理,memp_get_memorysize函数可以展开为:

#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
u32_t memp_get_memorysize(void)
{
  u32_t length=0;
    length=(
         MEM_ALIGNMENT-1
        + (LWIP_MEMPOOL(RAW_PCB,        MEMP_NUM_RAW_PCB,         sizeof(struct raw_pcb),        "RAW_PCB"))
        + (LWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        "UDP_PCB"))
        + ...
      );
    return length;
}
#undef LWIP_MEMPOOL

所以宏定义的作用域是同文件内从定义开始起作用,直到取消定义(undef)为止。可见lwip的作者写代码是多么的牛逼啊~

LwIP 中,关于 IP 字符串长度的宏定义主要涉及 IPv4 和 IPv6 地址的字符串表示形式。对于 IPv4 地址而言,通常使用 `INET_ADDRSTRLEN` 宏来定义其字符串长度,该值为 16,足以容纳类似 `"192.168.1.1"` 这样的 IPv4 地址字符串表示[^5]。 IPv6 地址的字符串表示更为复杂,因此 LwIP 提供了 `INET6_ADDRSTRLEN` 宏,其值为 46,用于确保可以存储最长格式的 IPv6 地址字符串,例如 `"fe80::1234:5678:9abc:def0"`。这些宏定义可以在 LwIP 的 `lwip/inet.h` 或 `lwip/inet6.h` 头文件中找到,具体取决于所使用的版本和配置[^6]。 以下是一个简单的代码示例,展示了如何在 LwIP 中使用 `inet_ntop` 函数将 IPv4 地址转换为字符串表示: ```c #include <stdio.h> #include "lwip/inet.h" int main() { struct in_addr ip; char ip_str[INET_ADDRSTRLEN]; // 将整数形式的 IP 地址转换为网络字节序的 32 位二进制形式 ip.s_addr = inet_addr("192.168.1.1"); // 将 IP 地址转换为字符串表示 if (inet_ntop(AF_INET, &ip, ip_str, sizeof(ip_str))) { printf("IP Address: %s\n", ip_str); } else { printf("inet_ntop failed\n"); } return 0; } ``` 对于 IPv6 地址的处理,代码逻辑与 IPv4 类似,但需要使用 `struct in6_addr` 和 `INET6_ADDRSTRLEN` 宏: ```c #include <stdio.h> #include "lwip/inet6.h" int main() { struct in6_addr ip6; char ip6_str[INET6_ADDRSTRLEN]; // 将 IPv6 地址字符串转换为二进制形式 if (inet_pton(AF_INET6, "2001:db8::1", &ip6) > 0) { // 将 IPv6 地址转换为字符串表示 if (inet_ntop(AF_INET6, &ip6, ip6_str, sizeof(ip6_str))) { printf("IPv6 Address: %s\n", ip6_str); } else { printf("inet_ntop failed\n"); } } else { printf("inet_pton failed\n"); } return 0; } ``` ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值