C语言使用nanopb对byte类型字段内字符串进行编解码问题求助
问题核心原因
你当前的实现属于跨网络/跨进程传输指针的典型错误:
struct flow_msg中的src_ap_name是char*指针类型,序列化时仅拷贝了struct本身的内存,指针指向的堆上的字符串内容并没有被打包进byteval字段- 你计算size时虽然加了字符串长度和结束符,但没有实际将字符串内容追加到struct内存的后面,发送的缓冲区里只有struct本身的内容,不包含实际字符串
- 接收端拿到的struct里的
src_ap_name是发送端的虚拟内存地址,在接收端进程的地址空间中完全无效,自然是空指针或者非法地址
正确的编码解码实现步骤
发送端处理步骤
建议优先将struct中的字符串指针替换为柔性数组,保证序列化内容是连续内存:
- 修改
struct flow_msg定义,将指针改为放在struct末尾的柔性数组:
struct flow_msg { uint32_t dst_addr; uint32_t src_addr; // 柔性数组放在struct最后一位,不占用struct本身的内存大小 char src_ap_name[]; };
- 一次性申请包含struct头和字符串的连续内存,填充内容:
size_t str_len = strlen(src_ap_name); // 总长度 = struct头长度 + 字符串长度 + 结束符'\0' size_t total_size = sizeof(struct flow_msg) + str_len + 1; struct flow_msg *flow_msg = malloc(total_size); flow_msg->dst_addr = 1; flow_msg->src_addr = 2; // 直接把字符串拷贝到柔性数组的位置 memcpy(flow_msg->src_ap_name, src_ap_name, str_len + 1);
- 直接将连续内存赋值给proto的
byteval字段编码即可:
obj_value->size = total_size; obj_value->data = flow_msg; // 确保nanopb编码时会把obj_value->data指向的total_size长度的连续内存全部写入byteval
接收端处理步骤
解码拿到byteval的data指针和长度后,直接强转即可读取字符串:
// 入参需要传入解码后的byteval长度做校验,避免越界 int handle_msg(void *f_msg, size_t msg_len) { struct flow_msg *flow_msg = (struct flow_msg *)f_msg; // 直接读取src_ap_name即可,是合法的以'\0'结尾的字符串 printf("src ap name: %s\n", flow_msg->src_ap_name); // 注意:f_msg指向的是nanopb的解码缓冲区,需要等使用完后再释放 }
不修改struct定义的替代方案
如果不想改动原有struct的指针定义,可以手动拼接序列化内容:
- 发送端手动申请缓冲区,先拷贝struct头再追加字符串:
struct flow_msg flow_msg = {0}; flow_msg.dst_addr = 1; flow_msg.src_addr = 2; size_t str_len = strlen(src_ap_name); size_t total_size = sizeof(flow_msg) + str_len + 1; uint8_t *send_buf = malloc(total_size); // 先拷贝struct的头部内容 memcpy(send_buf, &flow_msg, sizeof(flow_msg)); // 再把字符串拷贝到struct头部之后的位置 memcpy(send_buf + sizeof(flow_msg), src_ap_name, str_len +1); // 把send_buf和total_size传给proto的byteval编码
- 接收端手动拆分内容:
int handle_msg(void *f_msg, size_t msg_len) { struct flow_msg *flow_msg_head = (struct flow_msg *)f_msg; // 字符串存储在struct头部之后的位置 char *src_ap_name = (char *)f_msg + sizeof(struct flow_msg); // 可按需把字符串地址赋值给struct的指针字段,注意要保证f_msg的内存一直有效 flow_msg_head->src_ap_name = src_ap_name; }
内容的提问来源于stack exchange,提问作者Sergio Giménez
相关产品推荐
相关产品推荐

