在进行前,需要阅读下基础知识
基本知识:https://developers.google.com/protocol-buffers/docs/encoding
中文译文:http://www.wuzesheng.com/?p=1258
1. 从最简单的开始
message Info
{}
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
{}
Test::Info stInfo;
不设置成员值buf size:0, content:
Bin:
Hex:
3. required vs optional
message Info
{}
设置成员值和不设置成员值,输入跟上面的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;
}
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编码