You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言使用nanopb对byte类型字段内字符串进行编解码问题求助

问题核心原因

你当前的实现属于跨网络/跨进程传输指针的典型错误:

  • struct flow_msg 中的 src_ap_name 是char* 指针类型,序列化时仅拷贝了struct本身的内存,指针指向的堆上的字符串内容并没有被打包进byteval字段
  • 你计算size时虽然加了字符串长度和结束符,但没有实际将字符串内容追加到struct内存的后面,发送的缓冲区里只有struct本身的内容,不包含实际字符串
  • 接收端拿到的struct里的src_ap_name是发送端的虚拟内存地址,在接收端进程的地址空间中完全无效,自然是空指针或者非法地址
正确的编码解码实现步骤

发送端处理步骤

建议优先将struct中的字符串指针替换为柔性数组,保证序列化内容是连续内存:

  1. 修改struct flow_msg定义,将指针改为放在struct末尾的柔性数组:
struct flow_msg {
    uint32_t dst_addr;
    uint32_t src_addr;
    // 柔性数组放在struct最后一位,不占用struct本身的内存大小
    char src_ap_name[];
};
  1. 一次性申请包含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);
  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的指针定义,可以手动拼接序列化内容:

  1. 发送端手动申请缓冲区,先拷贝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编码
  1. 接收端手动拆分内容:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 00:36:02