google protocol buffer 编码详解(1)

在进行前,需要阅读下基础知识

基本知识:https://developers.google.com/protocol-buffers/docs/encoding

中文译文:http://www.wuzesheng.com/?p=1258


1. 从最简单的开始

 message Info

{
        optional int32 m_iValue = 1;

}


Test::Info stInfo;
stInfo.set_m_ivalue(2);


输出:

buf size:2, content:
Bin: 0000100000000010
Hex: 0802


解释: 00001000 (field number 1 左移3位) 00000010(2)


2. optional 定义的成员,如果没有设置值,那么不会被编码

 message Info

{
       optional int32 m_iValue = 1;

}


Test::Info stInfo;

不设置成员值

buf size:0, content:
Bin: 
Hex: 


3.  required vs optional

message Info

{
        required int32 m_iValue = 1;

}


设置成员值和不设置成员值,输入跟上面的optional是一样的,难道在c++的实现下,required和optional没区别?

diff查看2者生成的文件,cc文件区别如下:

optional.cc

bool Info::IsInitialized() const {


  return true;
}


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


  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
    "\n\ntest.proto\022\004Test\"\030\n\004Info\022\020\n\010m_iValue\030\001"
    " \001(\005", 44);//这里是001
  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
    "test.proto", &protobuf_RegisterTypes);
  Info::default_instance_ = new Info();
  Info::default_instance_->InitAsDefaultInstance();
  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_test_2eproto);
}


required.cc

bool Info::IsInitialized() const {
  if ((_has_bits_[0] & 0x00000001) != 0x00000001) return false;//多了这样一行


  return true;
}

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


  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
    "\n\ntest.proto\022\004Test\"\030\n\004Info\022\020\n\010m_iValue\030\001"
    " \002(\005", 44);//这里是002
  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
    "test.proto", &protobuf_RegisterTypes);
  Info::default_instance_ = new Info();
  Info::default_instance_->InitAsDefaultInstance();
  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_test_2eproto);
}


也就是说在required生成的文件中是有生成函数IsInitialized()来检测成员是否赋值,但是在真正serialize的时候并没有调用该函数去检查是否设置成员值。难道是需要程序员自己来主动调用该函数进行检查。


4. 负数的编码 int vs sint

message Info

{
        optional int32 m_iValue = 1;
}


Test::Info stInfo;

stInfo.set_m_ivalue(-1);

output:

buf size:11, content:
Bin: 0000100011111111111111111111111111111111111111111111111111111111111111111111111100000001
Hex: 08ffffffffffffffffff01


解释:64位的int(为什么是64位,不是指明32位吗?)-1,编码为8个f,因为pb每个byte需要一位来指明编码是否结束,每个byte的实际有效位只有7位,所以编码-1,需要10个byte(64除以7=9,余1)。综合起来,那么编码-1就需要11个byte


Test::Info stInfo;

stInfo.set_m_ivalue(-3);


buf size:11, content:
Bin: 0000100011111101111111111111111111111111111111111111111111111111111111111111111100000001
Hex: 08fdffffffffffffffff01

解释:-3的编码为fd+7个f,其它的解释同上


message Info
{
        optional sint32 m_iValue = 1;
}

 Test::Info stInfo;
 stInfo.set_m_ivalue(-1);


buf size:2, content:
Bin: 0000100000000001
Hex: 0801

解释:sint使用zig-zags来编码 (00001000是field number 偏移3位) 00000001为-1的zig-zags编码


你可能感兴趣的:(c,Google,buffer,byte,hex,output)