Protobuf介绍及简单使用(上)

目录

Protobuf

介绍

优势

protobuf语法

Specifying Field Rules

Data type

Data name

Number

Protobuf注释

保留字段与标识符

syntax关键词

分号

Protocol字段设置

获取成员值

 Packed 编码

optional default设置

用例

proto文件

编译proto文件

Family头文件

Family源码

用例

Makfile

运行

Caffe.proto文件

参考资料


本节主要解决上节遗留的问题,caffe中的数据结构文件在\src\caffe\proto\caffe.proto是个什么东东?如何才能看懂?需要先行补充下Protobuf的基础知识

Protobuf

介绍

Protobuf是由google开发的一套开源序列化协议框架,类似于XML,JSON,采用协议序列化用于数据存储与读取,与XML相比,定义了数据格式更加简单,数据访问接口可以自动化生成,加快了开发者开发速度,最新的版本为proto3已经支持Java,C++, Python, Java Lite, Ruby,JavaScript, Objective-c 以及C#, go,等常用语言.目前很多项目都在使用Protobuf.

官方链接(不需要翻墙):https://developers.google.cn/protocol-buffers/

官方文档:https://developers.google.cn/protocol-buffers/docs/overview#whynotxml

优势

既然xml已经使用非常广泛,那么为什么还需要Protocol Buffer?其优势主要有以下几点:

  • 简单
  • 比xml要小3到10倍,proto文件被编译成bin二进制文件
  • 比xml要快20到100倍
  • 结构更加清晰,不会产生歧义
  • 生成数据操作类更加容易,编程更加容易上手,访问接口代码基本都是自动生产

 例如定义一个person数据结构,里面包含name和email两个个人信息,xml定义如下:

<person>
    <name>John Doe</name>
    <email>jdoe@example.com</email>
  </person>

而使用protobuf定义时,其txt定义格式如下:

# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
  name: "John Doe"
  email: "jdoe@example.com"
}

是不是有点像python中的元组,采用key-value形式.

protobuf语法

上述是采用txt格式进行定义的,但是一般protobuf都是使用.proto文件,其语法格式使用Message定义

采用Message定义,person定义如下:

message Person {
  required string name = 1;
  required string email= 2;
}

意思是Person中的第一个字段为name,其数据类型为string,比选项;第二个字段为email,其数据类型为string,比选项.数据结构前加message关键词,意思是定义一个名为Person的数据结构,Message结构里面的每个成员结构格式如下:

[rules][data_type] [data_name] = [number]

分别解释其各个字段意思

Specifying Field Rules

该字段主要是定义该变量的规则,主要有三种规则:

  • required:该字段变量为必须的,实例中必须包含的字段.如果是在调试模式下编译 libprotobuf,则序列化一个未初始化的message 将将导致断言失败。在优化的构建中,将跳过检查并始终写入消息。但是,解析未初始化的消息将始终失败(通过从解析方法返回 false)
  • optional:该字段是可选的,可以设置也可以不设置该字段.如果未设置可选字段值,则使用默认值。对于简单类型,你可以指定自己的默认值,就像我们在示例中为电话号码类型所做的那样。否则,使用系统默认值:数字类型为 0,字符串为空字符串,bools 为 false。对于嵌入 message,默认值始终是消息的 “默认实例” 或 “原型”,其中没有设置任何字段。调用访问器以获取尚未显式设置的 optional(或 required)字段的值始终返回该字段的默认值。
  • repeated:该字段可以重复任意次数(包括零次).重复值的顺序将保留在 protocol buffer 中。可以将 repeated 字段视为动态大小的数组。

官方文档解释如下:

Data type

Protobuf支持常用的数据类型,支持的数据类型如下表:

.proto TypeNotesC++ TypeJava TypePython Type[2]Go Type
double doubledoublefloat*float64
float floatfloatfloat*float32
int32Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead.int32intint*int32
int64Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead.int64longint/long[3]*int64
uint32Uses variable-length encoding.uint32int[1]int/long[3]*uint32
uint64Uses variable-length encoding.uint64long[1]int/long[3]*uint64
sint32Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.int32intint*int32
sint64Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.int64longint/long[3]*int64
fixed32Always four bytes. More efficient than uint32 if values are often greater than 228.uint32int[1]int/long[3]*uint32
fixed64Always eight bytes. More efficient than uint64 if values are often greater than 256.uint64long[1]int/long[3]*uint64
sfixed32Always four bytes.int32intint*int32
sfixed64Always eight bytes.int64longint/long[3]*int64
bool boolbooleanbool*bool
stringA string must always contain UTF-8 encoded or 7-bit ASCII text.stringStringunicode (Python 2) or str (Python 3)*string
bytesMay contain any arbitrary sequence of bytes.stringByteStringbytes[]byte

基本能够满足其使用要求

Data name

data name为数据成员名

Number

Protobuf是采用key-value形式,将成员名映射为number,这样就能实现数据的序列化.每个数据字段都有唯一的数值型标识符.这些标识符用于标识字段在消息中的二进制格式,使用中的类型不应该随意改动。需要注意的是,[1-15]内的标识在编码时只占用一个字节,包含标识符和字段类型。[16-2047]之间的标识符占用2个字节。建议为频繁出现的消息元素使用[1-15]间的标识符。如果考虑到以后可能或扩展频繁元素,可以预留一些标识符。number最小为为1,最大为229 - 1, 2^{99}2^{99}or 536,870,911, 其中19000到19999为Protocol内部使用

Protobuf注释

在proto文件中经常需要添加注释对某个字段进行注释,支持C风格的双斜线//单行注释

保留字段与标识符

可以使用reserved关键字指定保留字段和保留标识符

message Foo {
    reserved 2, 15, 9 to 11;
    reserved "foo", "bar";
}

syntax关键词

sysntax关键字经常用到proto文件开头用来表明使用的是哪个proto版本

syntax = "proto2"

分号

行与行之间需要加分号,类似C语言.

Protocol字段设置

在对数据操作过程中经常需要对某个成员变量值进行修该,protocol提供了一系列很方便的API, 使用set函数,其格式为

set_[data_name]

例如定一个下面一个message

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

 分别设置其中的name,id以及email,其操作为:

Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");

获取成员值

获取成员值同样很简单,只有直接访问其成员即可,如下例子

fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;

 Packed 编码

在 proto2 中为我们提供了可选的设置 [packed = true],而这一可选项在 proto3 中已成默认设置。

packed 目前只能用于 repeated类型。

packed = true 主要使让 ProtoBuf 为我们把 repeated primitive 的编码结果打包,从而进一步压缩空间,进一步提高效率、速度。这里打包的含义其实就是:原先的 repeated 字段的编码结构为 Tag-Length-Value-Tag-Length-Value-Tag-Length-Value...,因为这些 Tag 都是相同的(同一字段),因此可以将这些字段的 Value 打包,即将编码结构变为 Tag-Length-Value-Value-Value... 

optional default设置

optional字段的默认值可以使用default来设置,例如:

optional int32 num = 1 [default = 0];

将默认值设值为0

用例

下面使用一个简单的例子说明Protobuf的基本使用方法.

proto文件

首先编写proto文件中,数据格式定义,代码如下:

syntax = "proto2";

message Person {
  required int32 age = 1;
  required string name = 2;
}

message Family {
  repeated Person person = 1;
}

编译proto文件

使用proto编译器编译proto文件,Protobuf安装不在详细描述,可自行网上查找,安装成功后,可以查看其版本

使用protoc命令编译proto文件,编译完成之后会自动生产.h和.cpp的代码

protoc --cpp_out=./  family.proto

自动生成的family.pb.cc和family.pb.h文件,以供后面使用

 protoc命令还可以将proto文件生成python和java文件接口,以供python和java使用,可以使用--help命令来查看protoc参数:

其中--cpp_out是生成c++接口文件以及源码,--jave_out是生成java接口,--python_out是生成python接口.

Family头文件

生成的Family头文件如下:

// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: family.proto

#ifndef PROTOBUF_family_2eproto__INCLUDED
#define PROTOBUF_family_2eproto__INCLUDED

#include <string>

#include <google/protobuf/stubs/common.h>

#if GOOGLE_PROTOBUF_VERSION < 2006000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers.  Please update
#error your headers.
#endif
#if 2006001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers.  Please
#error regenerate this file with a newer version of protoc.
#endif

#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/unknown_field_set.h>
// @@protoc_insertion_point(includes)

// Internal implementation detail -- do not call these.
void  protobuf_AddDesc_family_2eproto();
void protobuf_AssignDesc_family_2eproto();
void protobuf_ShutdownFile_family_2eproto();

class Person;
class Family;

// ===================================================================

class Person : public ::google::protobuf::Message {
 public:
  Person();
  virtual ~Person();

  Person(const Person& from);

  inline Person& operator=(const Person& from) {
    CopyFrom(from);
    return *this;
  }

  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
    return _unknown_fields_;
  }

  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
    return &_unknown_fields_;
  }

  static const ::google::protobuf::Descriptor* descriptor();
  static const Person& default_instance();

  void Swap(Person* other);

  // implements Message ----------------------------------------------

  Person* New() const;
  void CopyFrom(const ::google::protobuf::Message& from);
  void MergeFrom(const ::google::protobuf::Message& from);
  void CopyFrom(const Person& from);
  void MergeFrom(const Person& from);
  void Clear();
  bool IsInitialized() const;

  int ByteSize() const;
  bool MergePartialFromCodedStream(
      ::google::protobuf::io::CodedInputStream* input);
  void SerializeWithCachedSizes(
      ::google::protobuf::io::CodedOutputStream* output) const;
  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
  int GetCachedSize() const { return _cached_size_; }
  private:
  void SharedCtor();
  void SharedDtor();
  void SetCachedSize(int size) const;
  public:
  ::google::protobuf::Metadata GetMetadata() const;

  // nested types ----------------------------------------------------

  // accessors -------------------------------------------------------

  // required int32 age = 1;
  inline bool has_age() const;
  inline void clear_age();
  static const int kAgeFieldNumber = 1;
  inline ::google::protobuf::int32 age() const;
  inline void set_age(::google::protobuf::int32 value);

  // required string name = 2;
  inline bool has_name() const;
  inline void clear_name();
  static const int kNameFieldNumber = 2;
  inline const ::std::string& name() const;
  inline void set_name(const ::std::string& value);
  inline void set_name(const char* value);
  inline void set_name(const char* value, size_t size);
  inline ::std::string* mutable_name();
  inline ::std::string* release_name();
  inline void set_allocated_name(::std::string* name);

  // @@protoc_insertion_point(class_scope:Person)
 private:
  inline void set_has_age();
  inline void clear_has_age();
  inline void set_has_name();
  inline void clear_has_name();

  ::google::protobuf::UnknownFieldSet _unknown_fields_;

  ::google::protobuf::uint32 _has_bits_[1];
 mutable int _cached_size_;
  ::std::string* name_;
  ::google::protobuf::int32 age_;
  friend void  protobuf_AddDesc_family_2eproto();
  friend void protobuf_AssignDesc_family_2eproto();
  friend void protobuf_ShutdownFile_family_2eproto();

  void InitAsDefaultInstance();
  static Person* default_instance_;
};
// -------------------------------------------------------------------

class Family : public ::google::protobuf::Message {
 public:
  Family();
  virtual ~Family();

  Family(const Family& from);

  inline Family& operator=(const Family& from) {
    CopyFrom(from);
    return *this;
  }

  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
    return _unknown_fields_;
  }

  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
    return &_unknown_fields_;
  }

  static const ::google::protobuf::Descriptor* descriptor();
  static const Family& default_instance();

  void Swap(Family* other);

  // implements Message ----------------------------------------------

  Family* New() const;
  void CopyFrom(const ::google::protobuf::Message& from);
  void MergeFrom(const ::google::protobuf::Message& from);
  void CopyFrom(const Family& from);
  void MergeFrom(const Family& from);
  void Clear();
  bool IsInitialized() const;

  int ByteSize() const;
  bool MergePartialFromCodedStream(
      ::google::protobuf::io::CodedInputStream* input);
  void SerializeWithCachedSizes(
      ::google::protobuf::io::CodedOutputStream* output) const;
  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
  int GetCachedSize() const { return _cached_size_; }
  private:
  void SharedCtor();
 void SharedDtor();
  void SetCachedSize(int size) const;
  public:
  ::google::protobuf::Metadata GetMetadata() const;

  // nested types ----------------------------------------------------

  // accessors -------------------------------------------------------

  // repeated .Person person = 1;
  inline int person_size() const;
  inline void clear_person();
  static const int kPersonFieldNumber = 1;
  inline const ::Person& person(int index) const;
  inline ::Person* mutable_person(int index);
  inline ::Person* add_person();
  inline const ::google::protobuf::RepeatedPtrField< ::Person >&
      person() const;
  inline ::google::protobuf::RepeatedPtrField< ::Person >*
      mutable_person();

  // @@protoc_insertion_point(class_scope:Family)
 private:

  ::google::protobuf::UnknownFieldSet _unknown_fields_;

  ::google::protobuf::uint32 _has_bits_[1];
  mutable int _cached_size_;
  ::google::protobuf::RepeatedPtrField< ::Person > person_;
  friend void  protobuf_AddDesc_family_2eproto();
  friend void protobuf_AssignDesc_family_2eproto();
  friend void protobuf_ShutdownFile_family_2eproto();

  void InitAsDefaultInstance();
  static Family* default_instance_;
};
// ===================================================================


// ===================================================================

// Person

可以看到其提供set_name(),set_age()接口,以及其他接口以供使用

Family源码

family.pb.cc为自动生成的源码文件,是其接口实现,有兴趣可以分析一波

// Generated by the protocol buffer compiler.  DO NOT EDIT!
// source: family.proto

#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "family.pb.h"

#include <algorithm>

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/wire_format.h>
// @@protoc_insertion_point(includes)

namespace {

const ::google::protobuf::Descriptor* Person_descriptor_ = NULL;
const ::google::protobuf::internal::GeneratedMessageReflection*
  Person_reflection_ = NULL;
const ::google::protobuf::Descriptor* Family_descriptor_ = NULL;
const ::google::protobuf::internal::GeneratedMessageReflection*
  Family_reflection_ = NULL;

}  // namespace


void protobuf_AssignDesc_family_2eproto() {
  protobuf_AddDesc_family_2eproto();
  const ::google::protobuf::FileDescriptor* file =
    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
      "family.proto");
  GOOGLE_CHECK(file != NULL);
  Person_descriptor_ = file->message_type(0);
  static const int Person_offsets_[2] = {
    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Person, age_),
    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Person, name_),
  };
  Person_reflection_ =
    new ::google::protobuf::internal::GeneratedMessageReflection(
      Person_descriptor_,
      Person::default_instance_,
      Person_offsets_,
      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Person, _has_bits_[0]),
      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Person, _unknown_fields_),
      -1,
      ::google::protobuf::DescriptorPool::generated_pool(),
      ::google::protobuf::MessageFactory::generated_factory(),
      sizeof(Person));
  Family_descriptor_ = file->message_type(1);
  static const int Family_offsets_[1] = {
    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Family, person_),
  };
  Family_reflection_ =
    new ::google::protobuf::internal::GeneratedMessageReflection(
      Family_descriptor_,
      Family::default_instance_,
      Family_offsets_,
      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Family, _has_bits_[0]),
      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Family, _unknown_fields_),
      -1,
      ::google::protobuf::DescriptorPool::generated_pool(),
      ::google::protobuf::MessageFactory::generated_factory(),
      sizeof(Family));
}

namespace {

GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
inline void protobuf_AssignDescriptorsOnce() {
  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
                 &protobuf_AssignDesc_family_2eproto);
}

void protobuf_RegisterTypes(const ::std::string&) {
  protobuf_AssignDescriptorsOnce();
  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
    Person_descriptor_, &Person::default_instance());
  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
    Family_descriptor_, &Family::default_instance());
}

}  // namespace

void protobuf_ShutdownFile_family_2eproto() {
  delete Person::default_instance_;
  delete Person_reflection_;
  delete Family::default_instance_;
  delete Family_reflection_;
}

void protobuf_AddDesc_family_2eproto() {
  static bool already_here = false;
  if (already_here) return;
  already_here = true;
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
    "\n\014family.proto\"#\n\006Person\022\013\n\003age\030\001 \002(\005\022\014\n"
    "\004name\030\002 \002(\t\"!\n\006Family\022\027\n\006person\030\001 \003(\0132\007."
    "Person", 86);
  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
    "family.proto", &protobuf_RegisterTypes);
  Person::default_instance_ = new Person();
  Family::default_instance_ = new Family();
  Person::default_instance_->InitAsDefaultInstance();
  Family::default_instance_->InitAsDefaultInstance();
  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_family_2eproto);
}
// Force AddDescriptors() to be called at static initialization time.
struct StaticDescriptorInitializer_family_2eproto {
  StaticDescriptorInitializer_family_2eproto() {
    protobuf_AddDesc_family_2eproto();
  }
} static_descriptor_initializer_family_2eproto_;

// ===================================================================

#ifndef _MSC_VER
const int Person::kAgeFieldNumber;
const int Person::kNameFieldNumber;
#endif  // !_MSC_VER

Person::Person()
  : ::google::protobuf::Message() {
  SharedCtor();
  // @@protoc_insertion_point(constructor:Person)
}

void Person::InitAsDefaultInstance() {
}

Person::Person(const Person& from)
  : ::google::protobuf::Message() {
  SharedCtor();
  MergeFrom(from);
  // @@protoc_insertion_point(copy_constructor:Person)
}

void Person::SharedCtor() {
  ::google::protobuf::internal::GetEmptyString();
  _cached_size_ = 0;
  age_ = 0;
  name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
  ::memset(_has_bits_, 0, sizeof(_has_bits_));
}

Person::~Person() {
  // @@protoc_insertion_point(destructor:Person)
  SharedDtor();
}

void Person::SharedDtor() {
  if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
    delete name_;
  }
  if (this != default_instance_) {
  }
}

void Person::SetCachedSize(int size) const {
  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
  _cached_size_ = size;
  GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* Person::descriptor() {
  protobuf_AssignDescriptorsOnce();
  return Person_descriptor_;
}

const Person& Person::default_instance() {
  if (default_instance_ == NULL) protobuf_AddDesc_family_2eproto();
  return *default_instance_;
}

Person* Person::default_instance_ = NULL;

Person* Person::New() const {
  return new Person;
}

void Person::Clear() {
  if (_has_bits_[0 / 32] & 3) {
    age_ = 0;
    if (has_name()) {
      if (name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
        name_->clear();
      }
    }
  }
  ::memset(_has_bits_, 0, sizeof(_has_bits_));
  mutable_unknown_fields()->Clear();
}

bool Person::MergePartialFromCodedStream(
    ::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
  ::google::protobuf::uint32 tag;
  // @@protoc_insertion_point(parse_start:Person)
  for (;;) {
    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
    tag = p.first;
    if (!p.second) goto handle_unusual;
    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
      // required int32 age = 1;
      case 1: {
        if (tag == 8) {
          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
                 input, &age_)));
          set_has_age();
        } else {
          goto handle_unusual;
        } 
        if (input->ExpectTag(18)) goto parse_name;
        break;
      }

      // required string name = 2;
      case 2: {
        if (tag == 18) {
         parse_name:
          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
                input, this->mutable_name()));
          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
            this->name().data(), this->name().length(),
            ::google::protobuf::internal::WireFormat::PARSE,
            "name");
        } else {
          goto handle_unusual;
        } 
        if (input->ExpectAtEnd()) goto success;
        break;
      }

      default: {
      handle_unusual:
        if (tag == 0 ||
            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
          goto success;
        }
        DO_(::google::protobuf::internal::WireFormat::SkipField(
              input, tag, mutable_unknown_fields()));
        break;
      }
    }
  }
success:
  // @@protoc_insertion_point(parse_success:Person)
  return true;
failure: 
  // @@protoc_insertion_point(parse_failure:Person)
  return false;
#undef DO_
}

void Person::SerializeWithCachedSizes(
    ::google::protobuf::io::CodedOutputStream* output) const {
  // @@protoc_insertion_point(serialize_start:Person)
  // required int32 age = 1;
  if (has_age()) {
    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->age(), output);
  }

  // required string name = 2;
  if (has_name()) {
    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
      this->name().data(), this->name().length(),
      ::google::protobuf::internal::WireFormat::SERIALIZE,
     "name");
    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
      2, this->name(), output);
  }

  if (!unknown_fields().empty()) {
    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
        unknown_fields(), output);
  }
  // @@protoc_insertion_point(serialize_end:Person)
}

::google::protobuf::uint8* Person::SerializeWithCachedSizesToArray(
    ::google::protobuf::uint8* target) const {
  // @@protoc_insertion_point(serialize_to_array_start:Person)
  // required int32 age = 1;
  if (has_age()) {
    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->age(), target);
  }

  // required string name = 2;
  if (has_name()) {
    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
      this->name().data(), this->name().length(),
      ::google::protobuf::internal::WireFormat::SERIALIZE,
      "name");
    target =
      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
        2, this->name(), target);
  }

  if (!unknown_fields().empty()) {
    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
        unknown_fields(), target);
  }
  // @@protoc_insertion_point(serialize_to_array_end:Person)
  return target;
}

int Person::ByteSize() const {
  int total_size = 0;

  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
    // required int32 age = 1;
    if (has_age()) {
      total_size += 1 +
        ::google::protobuf::internal::WireFormatLite::Int32Size(
          this->age());
    }

    // required string name = 2;
    if (has_name()) {
      total_size += 1 +
        ::google::protobuf::internal::WireFormatLite::StringSize(
          this->name());
    }
  
  }
  if (!unknown_fields().empty()) {
    total_size +=
      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
        unknown_fields());
  }
  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
  _cached_size_ = total_size;
  GOOGLE_SAFE_CONCURRENT_WRITES_END();
  return total_size;
}

void Person::MergeFrom(const ::google::protobuf::Message& from) {
  GOOGLE_CHECK_NE(&from, this);
  const Person* source =
    ::google::protobuf::internal::dynamic_cast_if_available<const Person*>(
      &from);
  if (source == NULL) {
    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
  } else {
    MergeFrom(*source);
  }
}

void Person::MergeFrom(const Person& from) {
  GOOGLE_CHECK_NE(&from, this);
  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
    if (from.has_age()) {
      set_age(from.age());
    }
    if (from.has_name()) {
      set_name(from.name());
    }
  }
  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}

void Person::CopyFrom(const ::google::protobuf::Message& from) {
  if (&from == this) return;
  Clear();
  MergeFrom(from);
}

void Person::CopyFrom(const Person& from) {
  if (&from == this) return;
  Clear();
  MergeFrom(from);
}

bool Person::IsInitialized() const {
  if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false;

  return true;
}
void Person::Swap(Person* other) {
  if (other != this) {
    std::swap(age_, other->age_);
    std::swap(name_, other->name_);
    std::swap(_has_bits_[0], other->_has_bits_[0]);
    _unknown_fields_.Swap(&other->_unknown_fields_);
    std::swap(_cached_size_, other->_cached_size_);
  }
}

::google::protobuf::Metadata Person::GetMetadata() const {
  protobuf_AssignDescriptorsOnce();
  ::google::protobuf::Metadata metadata;
  metadata.descriptor = Person_descriptor_;
  metadata.reflection = Person_reflection_;
  return metadata;
}


// ===================================================================

#ifndef _MSC_VER
const int Family::kPersonFieldNumber;
#endif  // !_MSC_VER

Family::Family()
  : ::google::protobuf::Message() {
  SharedCtor();
  // @@protoc_insertion_point(constructor:Family)
}

void Family::InitAsDefaultInstance() {
}

Family::Family(const Family& from)
  : ::google::protobuf::Message() {
  SharedCtor();
  MergeFrom(from);
  // @@protoc_insertion_point(copy_constructor:Family)
}

void Family::SharedCtor() {
  _cached_size_ = 0;
  ::memset(_has_bits_, 0, sizeof(_has_bits_));
}

Family::~Family() {
  // @@protoc_insertion_point(destructor:Family)
  SharedDtor();
}

void Family::SharedDtor() {
  if (this != default_instance_) {
  }
}

void Family::SetCachedSize(int size) const {
  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
  _cached_size_ = size;
  GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const ::google::protobuf::Descriptor* Family::descriptor() {
  protobuf_AssignDescriptorsOnce();
  return Family_descriptor_;
}

const Family& Family::default_instance() {
  if (default_instance_ == NULL) protobuf_AddDesc_family_2eproto();
  return *default_instance_;
}

Family* Family::default_instance_ = NULL;

Family* Family::New() const {
  return new Family;
}

void Family::Clear() {
  person_.Clear();
  ::memset(_has_bits_, 0, sizeof(_has_bits_));
  mutable_unknown_fields()->Clear();
}

bool Family::MergePartialFromCodedStream(
    ::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure
  ::google::protobuf::uint32 tag;
  // @@protoc_insertion_point(parse_start:Family)
  for (;;) {
    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
    tag = p.first;
    if (!p.second) goto handle_unusual;
    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
      // repeated .Person person = 1;
      case 1: {
        if (tag == 10) {
         parse_person:
          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
                input, add_person()));
        } else {
          goto handle_unusual;
        }
        if (input->ExpectTag(10)) goto parse_person;
        if (input->ExpectAtEnd()) goto success;
        break;
      }

      default: {
      handle_unusual:
        if (tag == 0 ||
            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
          goto success;
        }
        DO_(::google::protobuf::internal::WireFormat::SkipField(
              input, tag, mutable_unknown_fields()));
        break;
      }
    }
  }
success:
  // @@protoc_insertion_point(parse_success:Family)
  return true;
failure:
  // @@protoc_insertion_point(parse_failure:Family)
  return false;
#undef DO_
}

void Family::SerializeWithCachedSizes(
    ::google::protobuf::io::CodedOutputStream* output) const {
  // @@protoc_insertion_point(serialize_start:Family)
  // repeated .Person person = 1;
  for (int i = 0; i < this->person_size(); i++) {
    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
      1, this->person(i), output);
  }

  if (!unknown_fields().empty()) {
    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
        unknown_fields(), output);
  }
  // @@protoc_insertion_point(serialize_end:Family)
}

::google::protobuf::uint8* Family::SerializeWithCachedSizesToArray(
    ::google::protobuf::uint8* target) const {
  // @@protoc_insertion_point(serialize_to_array_start:Family)
  // repeated .Person person = 1;
  for (int i = 0; i < this->person_size(); i++) {
    target = ::google::protobuf::internal::WireFormatLite::
      WriteMessageNoVirtualToArray(
        1, this->person(i), target);
  }

  if (!unknown_fields().empty()) {
    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
        unknown_fields(), target);
  }
  // @@protoc_insertion_point(serialize_to_array_end:Family)
  return target;
}

int Family::ByteSize() const {
  int total_size = 0;
 // repeated .Person person = 1;
  total_size += 1 * this->person_size();
  for (int i = 0; i < this->person_size(); i++) {
    total_size +=
      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
        this->person(i));
  }

  if (!unknown_fields().empty()) {
    total_size +=
      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
        unknown_fields());
  }
  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
  _cached_size_ = total_size;
  GOOGLE_SAFE_CONCURRENT_WRITES_END();
  return total_size;
}

void Family::MergeFrom(const ::google::protobuf::Message& from) {
  GOOGLE_CHECK_NE(&from, this);
  const Family* source =
    ::google::protobuf::internal::dynamic_cast_if_available<const Family*>(
      &from);
  if (source == NULL) {
    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
  } else {
    MergeFrom(*source);
  }
}

void Family::MergeFrom(const Family& from) {
  GOOGLE_CHECK_NE(&from, this);
  person_.MergeFrom(from.person_);
  mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}

void Family::CopyFrom(const ::google::protobuf::Message& from) {
  if (&from == this) return;
  Clear();
  MergeFrom(from);
}

void Family::CopyFrom(const Family& from) {
  if (&from == this) return;
  Clear();
  MergeFrom(from);
}

bool Family::IsInitialized() const {

  if (!::google::protobuf::internal::AllAreInitialized(this->person())) return false;
  return true;
}

void Family::Swap(Family* other) {
  if (other != this) {
    person_.Swap(&other->person_);
 mutable_unknown_fields()->MergeFrom(from.unknown_fields());
}

void Family::CopyFrom(const ::google::protobuf::Message& from) {
  if (&from == this) return;
  Clear();
  MergeFrom(from);
}

void Family::CopyFrom(const Family& from) {
  if (&from == this) return;
  Clear();
  MergeFrom(from);
}

bool Family::IsInitialized() const {

  if (!::google::protobuf::internal::AllAreInitialized(this->person())) return false;
  return true;
}

void Family::Swap(Family* other) {
  if (other != this) {
    person_.Swap(&other->person_);
    std::swap(_has_bits_[0], other->_has_bits_[0]);
    _unknown_fields_.Swap(&other->_unknown_fields_);
    std::swap(_cached_size_, other->_cached_size_);
  }
}

::google::protobuf::Metadata Family::GetMetadata() const {
  protobuf_AssignDescriptorsOnce();
  ::google::protobuf::Metadata metadata;
  metadata.descriptor = Family_descriptor_;
  metadata.reflection = Family_reflection_;
  return metadata;
}


// @@protoc_insertion_point(namespace_scope)

// @@protoc_insertion_point(global_scope)

用例

使用用例要求对Famyily添加两个成员,并分别设置其name和age,  用例先后先要加载生成的头文件famiy.pb.h,用例代码如下较为简单:

#include "family.pb.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(){
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  Family  family;
  Person* person;

  person = family.add_person();
  person->set_age(25);
  person->set_name("John");

  person = family.add_person();
  person->set_age(40);
  person->set_name("Tony");

  int size = family.person_size();

  printf("size : %d \r\n", size);
  for(int i = 0; i<size; i++)
  {
    Person psn=family.person(i);
    cout <<"Name :"<<psn.name()<<", age: "<<psn.age()<<endl;
  }

  return 0;
}

Makfile

编写makefile,不仅要编译编写的用例文件,还要编译自动生成的family.pb.cc文件,编译选项要加上

pkg-config --cflags --libs protobuf`

Makfile源码如下:

CC=g++
LIB_PATH=
HEAD_PATH=

TARGET = test
CPPFLAGS = -v -std=c++11
LIB_NAME =

CPP_FILE = family.pb.cc main.cpp

$(TARGET):
        $(CC) $(CPPFLAGS) $(CPP_FILE) $(LIB_PATH) $(LIB_NAME) $(HEAD_PATH) `pkg-config --cflags --libs protobuf` -o $@ 
clean:
        rm -f $(TARGET) 

运行

用例运行结果:

Caffe.proto文件

到目前为止Protobuf应该有所了解,上述资料足以我们能够了解src\caffe\proto\caffe.proto文件,Protobuf这层洋葱应该也可以剥掉.见caffe.proto文件开头

syntax = "proto2";

package caffe;

// Specifies the shape (dimensions) of a Blob.
message BlobShape {
  repeated int64 dim = 1 [packed = true];
}

message BlobProto {
  optional BlobShape shape = 7;
  repeated float data = 5 [packed = true];
  repeated float diff = 6 [packed = true];
  repeated double double_data = 8 [packed = true];
  repeated double double_diff = 9 [packed = true];

  // 4D dimensions -- deprecated.  Use "shape" instead.
  optional int32 num = 1 [default = 0];
  optional int32 channels = 2 [default = 0];
  optional int32 height = 3 [default = 0];
  optional int32 width = 4 [default = 0];
}

文件开头 syntax = "proto2";表明使用的是proto2版本

  • 在下行代码中看到一个关键字package,主要一个声名符,用来防止不同的消息类型有命名冲突。包的声明符会根据使用语言的不同影响生成的代码。对于C++,产生的类会被包装在C++的命名空间。package caffe,表明是在caffe的命名空间
  • 接下来定义一个BlobShape数据结构,数据结构中只包含一个字段dim,数据类型为int64,该数据类型为repeated,可以包含多个dim, 使用之前可以使用dim_size来计算其数据中有多少个dim,例如:
  • BlobProto结构定义,是Blob中比较关键的数据结构。在该数据中首先可以看到首先定义一个 BlobShape字段(ProtoBuf字段定义可以包含之前定义的数据结构),该字段是可选的,但是其number并不是为1,而是放到了后面。由此可以看到message中的字段定义并不是定义的第一个其number就为1,而是按照其经常使用频率进行调整。在BlobProto中经常使用到的就是4维参数,所以将4维参数放到前面,从1到4依次维num, channels, heigt, width。紧接着存放数据顺序维data, diff, shape, double_data, double_diff。在我们实际使用中定义message字段,也可以将经常使用到的频率较高的放到前面以提高访问效率及速度。
  • 接下来定义BlobProtoVector数据结构,包含字段类型为可选的BlobProto

剩余其他的不再解释,应该自己可以足够看懂,是不是并没有想象中的那么复杂,限于篇幅大小,将在下节中介绍protobuf中的文件读写:

Protobuf介绍及简单使用(下)之文件读写

参考资料

https://developers.google.cn/protocol-buffers/docs/overview#whynotxml

https://www.jianshu.com/p/d2bed3614259

https://blog.csdn.net/u014630623/article/details/88992609

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Huo的藏经阁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值