程式語言 - GNU - C/C++ - NanoPB Proto3(Callback)



參考資訊:
https://www.jianshu.com/p/cad578f48e0a
https://github.com/nanopb/nanopb/tree/master
https://github.com/afiskon/cpp-protobuf-example/tree/master
https://stackoverflow.com/questions/47704968/protoc-command-not-found-linux
https://stackoverflow.com/questions/62707863/how-to-encode-messages-with-map-using-google-protobuf-in-javascript-protocol

main.proto

syntax = "proto3";
  
message test {
    string v1 = 1;
    int32  v2 = 2;
  
    _opt opt  = 3;
    message _opt {
        string v1 = 1;
        int32  v2 = 2;
    }
}

main.c

#include <stdio.h>
#include <pb_encode.h>
#include <pb_decode.h>
 
#include "main.pb.h"
 
bool write_pb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
{
    char *src = *arg;
 
    pb_encode_tag_for_field(stream, field);
    pb_encode_string(stream, (uint8_t *)src, strlen(src));
    return true;
}
 
bool read_pb(pb_istream_t *stream, const pb_field_t *field, void **arg)
{
    int i = 0;
    char *dst = *arg;
    uint64_t value = 0;
 
    while (stream->bytes_left) {
        pb_decode_varint(stream, &value);
        *(dst + i) = value;
        i += 1;
    }
    return true;
}
 
int main(int argc, char **argv)
{
    char s1[255] = {0};
    char s2[255] = {0};
    char buf[255] = {0};
 
    test org = test_init_zero;
    org.v1.arg = "t1";
    org.v1.funcs.encode = write_pb;
    org.v2 = 100;
    org.has_opt = true;
    org.opt.v1.arg = "t2";
    org.opt.v1.funcs.encode = write_pb;
    org.opt.v2 = 200;
    pb_ostream_t os1 = pb_ostream_from_buffer(buf, sizeof(buf));
    pb_encode(&os1, test_fields, &org);
 
    test out = test_init_zero;
    out.v1.arg = &s1;
    out.v1.funcs.decode = read_pb;
    out.opt.v1.arg = &s2;
    out.opt.v1.funcs.decode = read_pb;
    pb_istream_t is2 = pb_istream_from_buffer(buf, os1.bytes_written);
    pb_decode(&is2, test_fields, &out);
 
    printf("v1: %s\n", s1);
    printf("v2: %d\n", out.v2);
    printf("opt.v1: %s\n", s2);
    printf("opt.v2: %d\n", out.opt.v2);
    return 0;
}

P.S. 由於Proto3預設使用Optional,因此,在做pb_encode()時,記得設定對應的Field成True,如上面例子的org.has_opt

編譯、執行

$ protoc --nanopb_out=-v:. main.proto
    Options file not found: main.options
    Options for main.proto: proto3: true
    Options for test: proto3: true
    Options for test.v1: proto3: true
    Options for test.v2: proto3: true
    Options for test.opt: proto3: true
    Options for test._opt: proto3: true
    Options for test._opt.v1: proto3: true
    Options for test._opt.v2: proto3: true
    Options file not found: main.options
    Options for main.proto: proto3: true
    Options for test: proto3: true
    Options for test.v1: proto3: true
    Options for test.v2: proto3: true
    Options for test.opt: proto3: true
    Options for test._opt: proto3: true
    Options for test._opt.v1: proto3: true
    Options for test._opt.v2: proto3: true

$ gcc main.c -o test main.pb.c -I. -lprotobuf-nanopb
$ ./test
    v1: t1
    v2: 100
    opt.v1: t2
    opt.v2: 200