目录

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 Type Notes C++ Type Java Type Python Type[2] Go Type
double   double double float *float64
float   float float float *float32
int32 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. int32 int int *int32
int64 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. int64 long int/long[3] *int64
uint32 Uses variable-length encoding. uint32 int[1] int/long[3] *uint32
uint64 Uses variable-length encoding. uint64 long[1] int/long[3] *uint64
sint32 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. int32 int int *int32
sint64 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. int64 long int/long[3] *int64
fixed32 Always four bytes. More efficient than uint32 if values are often greater than 228. uint32 int[1] int/long[3] *uint32
fixed64 Always eight bytes. More efficient than uint64 if values are often greater than 256. uint64 long[1] int/long[3] *uint64
sfixed32 Always four bytes. int32 int int *int32
sfixed64 Always eight bytes. int64 long int/long[3] *int64
bool   bool boolean bool *bool
string A string must always contain UTF-8 encoded or 7-bit ASCII text. string String unicode (Python 2) or str (Python 3) *string
bytes May contain any arbitrary sequence of bytes. string ByteString bytes []byte

基本能够满足其使用要求

Data name

data name为数据成员名

Number

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

Protobuf介绍及简单使用(上)相关推荐

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

    目录 Bin二进制文件 写bin文件API 用例一 读bin文件API 用例二 Prototxt文件 写Prototxt文件API 用例三 读Prototxt文件API 用例四 caffe中的prot ...

  2. SQL Server中追踪器Trace的介绍和简单使用

    原文:SQL Server中追踪器Trace的介绍和简单使用 一.What is Trace? 对于SQL Profiler这个工具相信大家都不是很陌生,没用过的朋友可以在SQL Server Man ...

  3. (一)Gluster 介绍及简单部署

    Gluster是一个可扩展的分布式文件系统,它将来自多个服务器的磁盘存储资源聚合到单个全局命名空间中. 一.介绍 能够支持扩展到几PB 支持数千的客户端 兼容POSIX Uses commodity ...

  4. S3C2440移植linux3.4.2内核之内核框架介绍及简单修改

    文章目录 uboot启动内核分析 简单配置内核 编译内核 设置机器ID 修改晶振 移植Linux3.4.2内核其他文章链接: S3C2440移植linux3.4.2内核之内核框架介绍及简单修改 S3C ...

  5. 新颖的自我介绍_简单新颖的自我介绍范文

    简单新颖的自我介绍范文 简单新颖的自我介绍范文1 各位考官好,今天能够站在这里参加面试,有机会向各位考官请教和学习,我感到非常的荣幸.希望通过这次面试能够把自己展示给大家,希望大家记住我.我叫.... ...

  6. git上传代码简单方法 简单git上传代码工具

    简单git上传代码工具 肯定有很多人和我一样,git上传时候搞不懂拉取,合并等一系列的代码冲突问题,往往可能覆盖掉自己今天写的代码,或者覆盖掉别人的代码. 下面给大家简单介绍一款操作比较简单的上传代码 ...

  7. 入侵介绍: 1。上传漏洞 2。暴库 3。注入 4。旁注 5。COOKIE诈骗

    入侵介绍: 1.上传漏洞 2.暴库 3.注入 4.旁注 5.COOKIE诈骗 1:上传漏洞,这个漏洞在DVBBS6.0时代被黑客们利用的最为猖獗,利用上传漏洞可以直接得到WEBSHELL,危害等级超级 ...

  8. Hive第一天——Hive介绍以及简单使用

    Hive第二天--Hive介绍以及简单使用 自己的话:黑发不知勤学早,白首方悔读书迟 每天都要保持前进! 一.什么是Hive 数据库: mysql.oracle.sqlserver.DB2.sqlit ...

  9. Helm模板常用语法介绍与简单应用场景

    Helm模板常用语法介绍与简单应用场景 文章目录 Helm模板常用语法介绍与简单应用场景 什么是Helm _help.tpl子模版 应用场景 预定义对象 关于变量 关键字及应用 函数 流程与控制 什么 ...

最新文章

  1. python对象一定要删除引用吗_在Python中删除一个对象和所有对它的引用?
  2. 【数据展示】matplotlib设置画面大小
  3. 表格过滤器_记录和管理零散信息,什么软件比 Excel 表格更方便
  4. 信用更正和贷方剩余数量
  5. 手机通讯录备份代码实现三
  6. 年夜饭之 -- 麻油鸡
  7. 流程控制: jQ Deferred 与 ES6 Promise 使用新手向入坑!
  8. vue+高德地图 点击地图获取经纬度和详细地址
  9. spyder python下载_Spyder Python软件-Spyder Python下载-最火软件站
  10. 微信小程序 时间插件 (可以选择日期+星期)
  11. 国人创造中文编程语言的优势
  12. iOS可持续化集成: Jenkins + bundler + cocoapods + shenzhen + fastlane + pgyer
  13. django相关报错知识整理
  14. 刻录linux安装光盘,如何将红旗Linux5的两个ISO安装光盘镜像刻录到一张DVD光盘上,做成安装光盘[原创]...
  15. 像向日葵一样活着——想起了从幼稚园到现在的同桌们
  16. 网站源码、模板分享(前端)
  17. 微信小程序实现表情包编辑
  18. 中国马铃薯全粉产业经营策略与销售渠道研究报告(2022-2027年)
  19. 用AkShare获取沪深京A股所有股票历史数据
  20. 【NVMe2.0b 15】NVMe SR-IOV

热门文章

  1. 微信小程序实战开发视频
  2. Linux环境Kafka安装配置
  3. SQL-22 统计各个部门对应员工涨幅的次数总和,给出部门编码dept_no、部门名称dept_name以及次数sum...
  4. 前端面试1:CSS布局
  5. AGG第四十四课 渲染问题:绘制较宽轮廓和尖锐边缘
  6. AeroFS 开源 SSMP 协议,包含 Java 和 Go 实现
  7. Objections vs. excuses
  8. mysql 实现master-slave 同步
  9. Unity+MVC:实现IDependencyResolver接口需要注意的地方
  10. Flash背景透明的代码