安装
sudo apt-update
sudo apt install -y protobuf-compiler protobuf-c-compiler
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修饰数据类型表示是一个数组的概念
编译
protoc [-I] --xxx_out=OUT_DIR file.proto
如
protoc --cpp_out=. example.proto
g++ main_test.cpp xxx.pb.cc -o main_test -lprotobuf
这样会报错
必须链接pthread(为什么)参考
g++ main.cpp example.pb.cc -o main_test -lprotobuf -pthread
需要注意的是,message的同级属性的num不能重复
编号也是有范围的,编号只能从`1 ~ 2^29 -1`之间进行取数,其中`19000 ~ 19999`不可取,因为这些编号已经被PB官方征用了!使用了编译就会出错;
在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()方法就能够设置值了。
序列化与反序列化
![[Pasted image 20240715100645.png]]
![[Pasted image 20240715100654.png]]
项目实例
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的字段,然后测试一下
#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;
}