战斗包子
protobuf学习记录

protobuf学习记录

安装

1
2
sudo apt-update
sudo apt install -y protobuf-compiler protobuf-c-compiler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
syntax = "proto2";

package protoTest; // namespace



message Example1 {

// 数字类型的集合

optional string name = 1;

optional int32 age = 2;

message EmbeddedMessage {

optional string stringVal = 1;

optional bytes bytesVal = 2;

} // 字段甚至可以又是一个message

// 字段规则:required -> 字段只能也必须出现 1 次

// 字段规则:optional -> 字段可出现 0 次或1次

// 字段规则:repeated -> 字段可出现任意多次(包括 0)

// 类型:int32、int64、sint32、sint64、string、32-bit ....

// 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)

// 字段规则 类型 名称 = 字段编号;



}

1、syntax 关键字表示使用的protobuf的版本,如不指定则默认使用 “proto2”

2、package关键字 表示“包”,生成目标语言文件后对应C++中的namespace命名空间,用于防止不同的消息类型间的命名冲突

3、message对应C++中的类, 内部包含各种属性, 其中repeated修饰数据类型表示是一个数组的概念

编译

1
protoc [-I] --xxx_out=OUT_DIR file.proto

1
protoc --cpp_out=. example.proto

1
g++ main_test.cpp xxx.pb.cc -o main_test -lprotobuf

这样会报错 必须链接pthread(为什么)参考

1
g++ main.cpp example.pb.cc -o main_test -lprotobuf -pthread

需要注意的是,message的同级属性的num不能重复

1
编号也是有范围的,编号只能从`1 ~ 2^29 -1`之间进行取数,其中`19000 ~ 19999`不可取,因为这些编号已经被PB官方征用了!使用了编译就会出错;
参考1

在C++中引用

package定义的命名空间会转换为C++中的namespase命名空间,message定义的类会转换为C++中国class定义的类,同时还会增加一系列与该属性字段相关的方法:

  • clear_xxx(): 清除改字段的值;
  • xxx(): 获取当前字段的值;
  • set_xxx(): 为当前字段设置值;
  • mutable_xxx() :获取当前字段的地址,对于自定义类型来说protoc不会为其生成set_xxx()的方法来设置值,因为它没办法预测用户到底想如何给自定义类型设置值,但是它会生成对应的mutable_xxx()函数,利用mutable_xxx()函数我们可以获取到当前字段的地址,然后再利用字段的内置set_xxx()方法进行对自定义类型中的各个字段进行初始化,对于protobuf内置的类型protoc不会为其生成mutable_xxx()方法,当然string等除外,这些基本类型利用set_xxx()方法就能够设置值了。

序列化与反序列化

![20240715100645.png] ![20240715100654.png]

项目实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
syntax = "proto2";

package rina.planning;

message TrafficLightState {

enum TLState {

INIT = 0;

LANE_FOLLOW = 1;

APPROACH = 2;

STOP = 3;

UNKNOWN_LIGHT = 4;

CROSSING = 5;

TURN_WAIT = 6;

}

optional TLState tl_state = 1;

}

交通灯信号,定义枚举变量TLState和一个TLState字段tl_state。

看上去项目中的protobuf主要的数据类型是double,bool和enum

在其中添加了一个tl_id的字段,然后测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>

#include <string>

#include <fstream>

#include "example.pb.h"



int main()

{

GOOGLE_PROTOBUF_VERIFY_VERSION;

// rina::planning::TrafficLightState state;

rina::planning::TrafficLightState state;

state.set_tl_state(rina::planning::TrafficLightState_TLState_APPROACH);

state.set_tl_id(1);

std::string str; // 创建字符串缓冲区

state.SerializeToString(&str);

std::cout << "序列化结果: " << str << std::endl;

rina::planning::TrafficLightState state2;

state2.ParseFromString(str);

std::cout << "反序列化结果: " << "state: " << state2.tl_state() << "id: " << state2.tl_id()<< std::endl;

return 0;

}
本文作者:战斗包子
本文链接:https://paipai121.github.io/2024/07/26/学习记录/protobuf学习记录/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可