动态生成Protobuf消息并将指针返回到它

Dynamically generate protobuf Message and return a pointer to it

本文关键字:指针 返回 Protobuf 消息 动态      更新时间:2023-10-16

首先,我对C 的经验不太经验,所以也许我在这里监督一些东西。我正在尝试通过以下代码从.proto文件中动态生成Protobuf消息:

int init_msg(const std::string & filename, protobuf::Arena* arena, protobuf::Message** new_msg){
  using namespace google::protobuf;
  using namespace google::protobuf::compiler;
  DiskSourceTree source_tree;
  source_tree.MapPath("file", filename);
  MuFiErCo error_mist;
  Importer imp(&source_tree, &error_mist);
  printf("Lade Datei:%s n", filename.c_str());
  const FileDescriptor* f_desc = imp.Import("file");
  const Descriptor* desc = f_desc->FindMessageTypeByName("TestNachricht");
  const Message* new_msg_proto = dmf.GetPrototype(desc);
  *new_msg = new_msg_proto->New(arena);
  //Debug
  cout << (*new_msg)->GetTypeName() << endl;
  return 0;
}
int main(int argc, char* argv[]){
  protobuf::Arena arena;
  protobuf::Message *adr2, *adr1;
  init_msg("schema-1.proto", &arena, &adr1);
  init_msg("schema-1.proto", &arena, &adr2);
  printf("MSG_Pointer: %p, %pn", adr1, adr2);
  cout << adr1->GetTypeName() << endl;
  arena.Reset();
  return 0;
}    

我以为如果我使用竞技场,新消息也可以在功能范围之外提供。但是,如果我尝试访问消息,总会有一个segfault。我想这是一个简单的错误,但我不知道,如何解决这个问题。

这是OUPUT:

Lade Datei:schema-1.proto 
packet.TestNachricht
Lade Datei:schema-1.proto 
packet.TestNachricht
MSG_Pointer: 0x1b293b0, 0x1b287f0
Speicherzugriffsfehler (Speicherabzug geschrieben)
我认为,

问题是,当提交的文字者等人被摧毁时 init_msg返回,留下新创建的消息,无法 询问其.proto定义。您需要移动进口商 实例向主机保持生命。这与 竞技场。 - Igor Tandetnik

那是解决方案。

这是一些有效的示例代码

#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <memory>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/arena.h>

using namespace std;
using namespace google::protobuf;

class MuFiErCo : public compiler::MultiFileErrorCollector
{
public:
    void AddError(const string & filename, int line, int column, const string & message){
        printf("Err: %sn", message.c_str());
    }
    void AddWarning(const string & filename, int line, int column, const string & message){
        printf("Warn: %sn", message.c_str());
    }
};

compiler::Importer* init_proto_dir(Arena* arena, const std::string &root_dir){
    using namespace compiler;
    static DiskSourceTree source_tree;
    source_tree.MapPath("", root_dir);
    static MuFiErCo error_mist;
    static Importer* imp = Arena::Create<Importer>(arena, &source_tree, &error_mist);
    return imp;
}

void init_proto_def(compiler::Importer* imp, const std::string &proto_file){
    using namespace compiler;
    imp->Import(proto_file);
    return;
}

Message* init_msg(compiler::Importer* imp, Arena* arena, const std::string &msg_name){
    const DescriptorPool* pool = imp->pool();
    static DynamicMessageFactory dmf;
    const Descriptor* desc = pool->FindMessageTypeByName(msg_name);
    const Message* msg_proto = dmf.GetPrototype(desc);
    return msg_proto->New(arena);
}

int set_value(Message* msg, const char* value_name, unsigned long int value){
    const Message::Reflection* reflec = msg->GetReflection();
    const Descriptor* desc = msg->GetDescriptor();
    const FieldDescriptor* fdesc = desc->FindFieldByName(value_name);
    reflec->SetUInt64(msg, fdesc, value);
    return 0;
}

int main(int argc, char* argv[]){
    Arena arena;
    compiler::Importer* imp = init_proto_dir(&arena, "");
    init_proto_def(imp, "schema-1.proto");
    Message* msg = init_msg(imp, &arena, "packet.TestNachricht");
    set_value(msg, "zahl", 23434);
    cout << msg->DebugString() << endl;
    return 0;
}