【问题标题】:How can I get more details about errors generated during protobuf parsing? (C++)如何获取有关 protobuf 解析期间生成的错误的更多详细信息? (C++)
【发布时间】:2026-02-08 10:15:01
【问题描述】:

我是 protobuf (C++) 的新手,我的代码在解析消息时失败。如何获得有关所发生错误的更多详细信息?

示例

下面的 sn-p 说明了这个问题:

const bool ok=my_message.ParseFromCodedStream(&stream);
if(ok){
    std::cout<< "message parsed. evidence:\n"<< my_message.DebugString();
}
else{
    std::cerr<< "error parsing protobuf\n";
    //HOW CAN I GET A REASON FOR THE FAILURE HERE?
}

【问题讨论】:

  • 我认为您一般无法获得详细信息,但您可以使用 ParsePartialFromCodedStream 接受缺少必填字段的邮件。

标签: c++ error-handling protocol-buffers


【解决方案1】:

如果您查看 protobuf 代码,您会发现它使用自己的日志记录系统 - 基于宏。默认情况下,所有这些消息都会发送到stderr,但您可以使用SetLogHandler() 在程序中捕获它们:

typedef void LogHandler(LogLevel level, const char* filename, int line,
                        const std::string& message);

可能的解决方案是制作你自己的errno-like 机制(对不起C++11-ishness):

typedef LogMessage std::tuple<LogLevel, std::string, int, std::string>;  // C++11
typedef LogStack std::list<LogMessage>;

namespace {

LogStack stack;
bool my_errno;

}  // namespace

void MyLogHandler(LogLevel level, const char* filename, int line,
                  const std::string& message) {
  stack.push_back({level, filename, line, message});  // C++11.
  my_errno = true;
}

protobuf::SetLogHandler(MyLogHandler);

bool GetError(LogStack* my_stack) {
  if (my_errno && my_stack) {
    // Dump collected logs.
    my_stack->assign(stack.begin(), stack.end());
  }

  stack.clear();
  bool old_errno = my_errno;
  my_errno = false;

  return old_errno;
}

并在您的代码中使用它:

...
else {
    std::cerr<< "error parsing protobuf" << std::endl;
    LogStack my_stack;
    if (GetError(&my_stack) {
      // Handle your errors here.
    }
}

我的示例代码的主要缺点 - 它不适用于多线程。但这可以自己解决。

【讨论】:

  • 第一:永远不应该(IMO)为使用 C++11 道歉。第二:感谢您的出色回答:-)
【解决方案2】:

有时错误信息会打印到控制台,但仅此而已。无法通过 API 获取额外的错误信息。

也就是说,无论如何只有两种错误:

  1. 缺少必填字段。 (在这种情况下,信息应打印到控制台。)
  2. 数据已损坏。它根本不是由有效的 protobuf 实现生成的——它甚至不是不同类型的 protobuf,它根本不是 protobuf。

如果您看到后一种情况,您需要比较发送方和接收方的数据,并找出不同的原因。请记住,您提供给 protobuf 解析器的数据不仅必须是相同的字节,而且必须在相同的位置结束——protobuf 解析器不知道消息在哪里结束,除非接收到 EOF。这意味着,如果您将多条消息写入流,则需要在数据之前写入大小,并确保在传递给 protobuf 解析器之前在接收端只读取那么多字节。

【讨论】:

  • 感谢 EOF 提示!
最近更新 更多