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

如何在C++ Protobuf中使用bytes类型(编码/解码及字段填充)

如何用pb_callback_t填充Protobuf的bytes字段?

我定义了如下Protobuf消息:

syntax = "proto3";

package package;

message WriteBlock
{
  uint32 address = 1;
  uint32 size = 2;
  bytes data = 3;
}

已创建该类型变量并初始化:

package_WriteBlock writeBlock = package_WriteBlock_init_zero;

原本以为Protobuf的bytes类型会被转为string,但生成的代码里对应的字段类型是pb_callback_t:

typedef struct _package_WriteBlock {
    uint32_t address;
    uint32_t size;
    pb_callback_t data;
} package_WriteBlock;

pb_callback_t的定义如下:

typedef struct pb_callback_s pb_callback_t;
struct pb_callback_s {
    /* Callback functions receive a pointer to the arg field.
     * You can access the value of the field as *arg, and modify it if needed.
     */
    union {
        bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg);
        bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
    } funcs;

    /* Free arg for use by callback */
    void *arg;
};

请问如何将std::uint8_t byteArray[20]存入data字段?是否需要使用encode()?这些参数的含义是什么?


核心前提

你用的是Nanopb(轻量型Protobuf实现,专为嵌入式/资源受限环境设计),它用pb_callback_t处理动态长度或较大的bytes/string字段,避免预分配固定大小的缓冲区。

实现步骤

要填充data字段,你需要给pb_callback_t绑定一个自定义的编码回调函数,在序列化时自动把byteArray的数据写入输出流。

1. 编写编码回调函数

这个函数负责把你的字节数组写入Nanopb的输出流,参数含义如下:

  • pb_ostream_t *stream:Nanopb的输出流对象,所有序列化数据都会写入这里(可以是内存缓冲区或文件)
  • const pb_field_t *field:当前处理的字段元数据(比如字段ID、类型,一般不需要修改)
  • void * const *arg:指向你传入的自定义数据指针(这里就是你的byteArray或包含数据+长度的结构体)

示例实现:

#include <pb_encode.h>

// 传递字节数组和长度的辅助结构体
typedef struct {
    const uint8_t* data;
    size_t length;
} ByteArrayData;

// 自定义编码回调
bool encode_bytes_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
    ByteArrayData* byte_data = (ByteArrayData*)*arg;
    
    // 把字节数组写入输出流
    if (!pb_write(stream, byte_data->data, byte_data->length)) {
        return false; // 写入失败返回false,终止序列化
    }
    return true;
}

2. 初始化WriteBlock变量和回调

把回调函数绑定到writeBlock.data,并传入你的字节数组数据:

#include <stdint.h>

// 你的目标字节数组
uint8_t byteArray[20] = {0x01, 0x02, 0x03, /* ... 其他数据 ... */};

// 初始化辅助结构体
ByteArrayData byte_data = {
    .data = byteArray,
    .length = sizeof(byteArray) // 固定长度20
};

// 初始化WriteBlock
package_WriteBlock writeBlock = package_WriteBlock_init_zero;
writeBlock.address = 0x1234; // 示例地址
writeBlock.size = sizeof(byteArray); // 示例大小

// 绑定回调和数据
writeBlock.data.funcs.encode = encode_bytes_callback;
writeBlock.data.arg = &byte_data;

3. 序列化整个消息

调用Nanopb的pb_encode函数,此时会自动触发encode_bytes_callback,把byteArray的数据序列化到输出流中:

uint8_t buffer[128]; // 足够容纳序列化后的消息
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));

// 序列化WriteBlock
if (!pb_encode(&stream, package_WriteBlock_fields, &writeBlock)) {
    // 序列化失败,处理错误
    printf("Encode failed: %s\n", PB_GET_ERROR(&stream));
    return -1;
}

// 此时buffer里就是序列化后的Protobuf数据,长度为stream.bytes_written

关键说明

  • 为什么用回调?Nanopb默认对bytes/string字段如果没指定max_size,会生成pb_callback_t,这样可以避免预分配大缓冲区,适合嵌入式场景。
  • 如果你的字节数组长度固定且很小,也可以在.proto文件里给data字段加[nanopb.max_size = 20]选项,重新生成代码后会直接变成固定大小的数组,不需要回调。

内容的提问来源于stack exchange,提问作者peter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:57:18