我正在使用protobuf创建一个支持许多不同消息的系统,我依赖于动态消息,工厂和反射界面。除了字符串类型,我可以获取并设置所有不同的字段数据类型(uint32,int64,...等)。当我尝试使用字符串数据类型的字段的任何getter或setter时,我的代码段错误。第一块代码是最小的例子(对不起,这很长,但是进口商,工厂等需要到位才有意义)。第二块代码是我一直用于测试的proto文件。我的问题是如何访问字符串字段以设置或获取数据。
#include <vector>
#include <string>
#include <sstream>
#include <dirent.h>
#include <stdexcept>
#include <iostream>
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/compiler/parser.h>
#include <google/protobuf/descriptor_database.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/arena.h>
class errCollector : public google::protobuf::compiler::MultiFileErrorCollector
{
public:
~errCollector() {};
void AddError(const std::string& filename,
int line, int column, const std::string& message) {};
};
google::protobuf::compiler::Importer* createImporter( );
void buildSubMessages(const google::protobuf::Descriptor* desc,
google::protobuf::Message* msg, const google::protobuf::Reflection* ref,
google::protobuf::DynamicMessageFactory* factory);
int main(int argc, char** argv)
{
// Usage: ProtobufMinimalExample <message type name>
std::string msgType(argv[1]);
// Error message stream
std::ostringstream msgStream;
// Create the importer object which holds all of the .proto files.
google::protobuf::compiler::Importer* importer = createImporter();
// Create the descriptor pool which holds all of the message descriptors.
const google::protobuf::DescriptorPool* pool(importer->pool());
// Create an object to hold the top-level message.
google::protobuf::Message* mutableMsg;
// Create an object to hold the top-level message descriptor.
const google::protobuf::Descriptor* messageDesc;
// Create a message to hold the prototype description of the dynamic message
const google::protobuf::Message* protoTypeMsg;
// Create the message factory.
google::protobuf::DynamicMessageFactory* factory( new google::protobuf::DynamicMessageFactory);
messageDesc = pool->FindMessageTypeByName(msgType);
protoTypeMsg = factory->GetPrototype(messageDesc);
mutableMsg = protoTypeMsg->New();
// Get a submessage in the field named "yellow".
const google::protobuf::FieldDescriptor* field = messageDesc->FindFieldByName("yellow");
const google::protobuf::Descriptor* subMsgDesc = field->message_type();
const google::protobuf::Message* subProtoTypeMsg = factory->GetPrototype(subMsgDesc);
google::protobuf::Message* subMutableMsg = subProtoTypeMsg->New();
const google::protobuf::Reflection* subReflection = (subMutableMsg->GetReflection());
const google::protobuf::Descriptor* subMutableDesc = subMutableMsg->GetDescriptor();
std::string* name = new std::string();
// Segfault
//const google::protobuf::FieldDescriptor* subField = subMutableDesc->FindFieldByName("name");
//subReflection->SetString(mutableMsg, subField, "Hello");
//subReflection->GetString(*(mutableMsg), subField);
//subReflection->GetStringReference(*(mutableMsg), subField, name);
// Works
//const google::protobuf::FieldDescriptor* subField = subMutableDesc->FindFieldByName("score");
//subReflection->SetUInt32(mutableMsg, subField, 9);
//subReflection->GetUInt32(*(mutableMsg), subField);
return 0;
}
google::protobuf::compiler::Importer* createImporter()
{
google::protobuf::compiler::DiskSourceTree srcTree;
errCollector error;
google::protobuf::compiler::Importer* fdProtoImporter(new google::protobuf::compiler::Importer(&srcTree, &error));
const char* protoFilePath = "./proto";
struct dirent* entry;
DIR* dp;
std::vector<std::string> importProtoFilenames;
dp = opendir(protoFilePath);
unsigned char isFile = 0x8;
while( (entry = readdir(dp)) )
{
if(entry->d_type != isFile)
continue;
importProtoFilenames.push_back(std::string(entry->d_name));
}
closedir(dp);
srcTree.MapPath("", protoFilePath);
for( auto protoFilename : importProtoFilenames )
{
if(fdProtoImporter->Import(protoFilename) == NULL)
{
continue;
}
}
return std::move(fdProtoImporter);
}
message SSL_Referee {
required uint64 packet_timestamp = 1;
enum Stage {
NORMAL_FIRST_HALF_PRE = 0;
NORMAL_FIRST_HALF = 1;
NORMAL_HALF_TIME = 2;
NORMAL_SECOND_HALF_PRE = 3;
NORMAL_SECOND_HALF = 4;
EXTRA_TIME_BREAK = 5;
EXTRA_FIRST_HALF_PRE = 6;
EXTRA_FIRST_HALF = 7;
EXTRA_HALF_TIME = 8;
EXTRA_SECOND_HALF_PRE = 9;
EXTRA_SECOND_HALF = 10;
PENALTY_SHOOTOUT_BREAK = 11;
PENALTY_SHOOTOUT = 12;
POST_GAME = 13;
}
required Stage stage = 2;
optional sint32 stage_time_left = 3;
// These are the "fine" states of play on the field.
enum Command {
// All robots should completely stop moving.
HALT = 0;
// Robots must keep 50 cm from the ball.
STOP = 1;
// A prepared kickoff or penalty may now be taken.
NORMAL_START = 2;
// The ball is dropped and free for either team.
FORCE_START = 3;
// The yellow team may move into kickoff position.
PREPARE_KICKOFF_YELLOW = 4;
// The blue team may move into kickoff position.
PREPARE_KICKOFF_BLUE = 5;
// The yellow team may move into penalty position.
PREPARE_PENALTY_YELLOW = 6;
// The blue team may move into penalty position.
PREPARE_PENALTY_BLUE = 7;
// The yellow team may take a direct free kick.
DIRECT_FREE_YELLOW = 8;
// The blue team may take a direct free kick.
DIRECT_FREE_BLUE = 9;
// The yellow team may take an indirect free kick.
INDIRECT_FREE_YELLOW = 10;
// The blue team may take an indirect free kick.
INDIRECT_FREE_BLUE = 11;
// The yellow team is currently in a timeout.
TIMEOUT_YELLOW = 12;
// The blue team is currently in a timeout.
TIMEOUT_BLUE = 13;
// The yellow team just scored a goal.
// For information only.
// For rules compliance, teams must treat as STOP.
GOAL_YELLOW = 14;
// The blue team just scored a goal.
GOAL_BLUE = 15;
}
required Command command = 4;
// The number of commands issued since startup (mod 2^32).
required uint32 command_counter = 5;
// The UNIX timestamp when the command was issued, in microseconds.
// This value changes only when a new command is issued, not on each packet.
required uint64 command_timestamp = 6;
// Information about a single team.
message TeamInfo {
// The team's name (empty string if operator has not typed anything).
required string name = 1;
// The number of goals scored by the team during normal play and overtime.
required uint32 score = 2;
// The number of red cards issued to the team since the beginning of the game.
required uint32 red_cards = 3;
// The amount of time (in microseconds) left on each yellow card issued to the team.
// If no yellow cards are issued, this array has no elements.
// Otherwise, times are ordered from smallest to largest.
repeated uint32 yellow_card_times = 4 [packed=true];
// The total number of yellow cards ever issued to the team.
required uint32 yellow_cards = 5;
// The number of timeouts this team can still call.
// If in a timeout right now, that timeout is excluded.
required uint32 timeouts = 6;
// The number of microseconds of timeout this team can use.
required uint32 timeout_time = 7;
// The pattern number of this team's goalie.
required uint32 goalie = 8;
}
// Information about the two teams.
required TeamInfo yellow = 7;
required TeamInfo blue = 8;
}
答案 0 :(得分:0)
// Segfault
const google::protobuf::FieldDescriptor* subField = subMutableDesc->FindFieldByName("name");
subReflection->SetString(mutableMsg, subField, "Hello");
subReflection->GetString(*(mutableMsg), subField);
subReflection->GetStringReference(*(mutableMsg), subField, name);
我相信您在此代码中撰写mutableMsg
的位置,您的意思是subMutableMsg
。因此,您尝试修改错误的消息,并且您传入的消息具有不同的布局,因此当反射代码尝试访问字符串类型的字段时,它最终会尝试遵循指针无效。
// Works
const google::protobuf::FieldDescriptor* subField = subMutableDesc->FindFieldByName("score");
subReflection->SetUInt32(mutableMsg, subField, 9);
subReflection->GetUInt32(*(mutableMsg), subField);
这种情况不是&#34;工作&#34;,它只是没有段错误。我相信这段代码实际上会破坏mutableMsg
中的内存,但由于你正在修改一个简单的原始字段,反射代码不会尝试跟随任何指针,因此不会出现段错误。