当前位置:首页 > c++ > 正文内容

c++如何编译和使用probuf

xuwenyan6个月前 (08-10)c++142

关于protobuf的介绍,请阅读文章关于protobuf的介绍和优缺点,这里不做过多介绍,直接开始使用教程。

编译protobuf

1:安装cmake

cmake用于生成protobuf的VisualStudio的工程,需要通过VisualStudio编译生成libprotobuf.lib和protoc.exe文件。

2:下载protobuf代码

打开https://github.com/protocolbuffers/protobuf/releases/tag/v21.5,c++使用选择下载文件 protobuf-cpp-xxx.tar.gz 或 protobuf-cpp-xxx.zip文件。

image.png

下载成功后解压文件。

3:通过cmake生成vs工程

  1. 打开cmake,填入protobuf目录下的cmake文件夹到Where is the source code编辑框

  2. 随便填入一个生成目录到Where to build the binaries编辑框,比如protobuf目录下的build文件夹

  3. 点击Configure,选择生成需要的vs版本,点击确定

  4. Configure完成后点击Generate生成vs工程

image.png

打开生成目录,找到protobuf.sln文件,打开并编译 libprotobuf-lite(l ibprotobuf-lite 没有描述符和反射等某些功能,但体积会小一个数量级,如果需要可以选择编译libprotobuf) 和 protoc 工程,会生成 libprotobuf-lite.lib(debug模式会在文件名末尾加d) 和 protoc.exe文件

image.png

image.png

配置工程依赖

1:复制文件所需文件到工程对应目录下

  • 把 protobuf/src/ 目录下的 google 文件夹拷贝到工程目录下

  • 把 protobuf输出目录下的 libprotobuf-lite.lib 和 protoc.exe 分 Debug 和 Release环境分别拷贝到工程的输出目录下

image.png

image.png

image.png

2:配置附加包含目录和附加库目录

打开工程解决方案,右击工程选择属性,C/C++ -> 常规 -> 附加包含目录,填入当前目录 ./

image.png

右击工程选择属性,连接器 -> 常规 -> 附加库目录,填入 libproto-lite.lib 所在目录, 我选择的是输出目录,可以使用变量 $(OutDir)

image.png

3:依赖静态库

可以选择在 链接器 -> 输入 -> 附加依赖项 中填入 libproto-lite.lib文件,也可以选择在代码中链接,看个人习惯,我喜欢在代码中链接

创建links.cpp文件并打开

分 Debug 和 Release 分别链接 libprotobuf,代码如下:

#ifdef _DEBUG
#pragma comment(lib, "libprotobuf-lited.lib")
#else
#pragma comment(lib, "libprotobuf-lite.lib")
#endif // DEBUG

proto文件的编写和配置

1:创建.proto文件

首先在工程目录下创建一个文件夹用于专门存储.proto文件,比如我创建的是 protobuf 文件夹

image.png

打开文件夹,创建一个后缀为 .proto 的文件,比如 message.proto

image.png

2:编写.proto文件

打开 message.proto 文件,配置需要的字段,比如:

syntax = "proto3";
package tutorial;
option optimize_for = LITE_RUNTIME;

message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    optional string number = 1;
    optional PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

每个字段都必须使用optional,repeated,required标签修饰,注意:proto3已经不支持required标签,并且proto3不支持设置默认值。

  • optional: 该字段可以设置也可以不设置。如果未设置可选字段值,则使用默认值。对于简单类型,您可以指定自己的默认值,就像我们在示例中为电话号码所做的那样type否则,使用系统默认值:数字类型为零,字符串为空字符串,布尔值为 false。对于嵌入式消息,默认值始终是消息的“默认实例”或“原型”,没有设置任何字段。调用访问器以获取未显式设置的可选(或必需)字段的值始终返回该字段的默认值。

  • repeated:该字段可以重复任意次数(包括零次)。重复值的顺序将保存在协议缓冲区中。将重复字段视为动态大小的数组。

  • required:必须提供该字段的值,否则该消息将被视为“未初始化”。如果libprotobuf在调试模式下编译,序列化未初始化的消息将导致断言失败。在优化的构建中,会跳过检查并且无论如何都会写入消息。但是,解析未初始化的消息总是会失败(通过false从 parse 方法返回)。除此之外,必填字段的行为与可选字段完全相同。

syntax 为显示的指定proto的版本。

package 指定包名,避免与其它 .proto文件的字段冲突,在C++中,package其实就是生成了一个名字控件(namespace)。

message 会生成一个类,类里面包含的就是每个字段的变量和一些操作方法。

每个字段后面都必须有一个字段编号“=数字;”它可以不是递增的,但每个message作用域内它必须是唯一的。

如果链接的是 libproto-lite.lib 库,那么必须在 .proto 文件开头加上 “option optimize_for = LITE_RUNTIME”;

关于required被在proto3移除的原因大概是因为:

您应该非常小心将字段标记为required如果在某些时候您希望停止编写或发送必填字段,则将该字段更改为可选字段将会有问题——老读者会认为没有此字段的消息不完整,可能会无意中拒绝或丢弃它们。您应该考虑为您的缓冲区编写特定于应用程序的自定义验证例程。在 Google 内部,required字段是非常不受欢迎的;proto2 语法中定义的大多数消息optional仅使用repeated(Proto3 根本不支持required字段。)

更多关于protobuf的详细介绍可以参略谷歌文档:https://developers.google.com/protocol-buffers?hl=cn

3:配置.proto文件自定义生成

  • 右击工程,选择 添加 -> 新建筛选器,创建一个筛选器,比如protobuf

  • 右击创建的筛选器,添加 -> 现有项,找到刚才创建的 message.proto 文件,选择添加即可

image.png

  • 右击 message.pro 文件,配置属性 -> 常规 -> 项类型,选择 “自定义生成工具”

  • 右击 message.pro 文件,配置属性 -> 自定义生成工具 -> 命令行,填入 “$(OutDir)protoc.exe --proto_path=$(ProjectDir)protobuf --cpp_out=$(ProjectDir) %(FullPath)”

    这是使用protoc.exe编译 message.proto 文件,生成 message.pb.cc 和 message.pb.h 文件,这里填入的就是执行protoc.exe的命令行

protoc --proto_path=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto

    $SRC_DIR是.proto所在的目录,$DST_DIR是需要输出的目录

  • 右击 message.pro 文件,配置属性 -> 自定义生成工具 -> 输出,填入 “$(ProjectDir)%(Filename).pb.cc;$(ProjectDir)%(Filename).pb.h;%(Outputs)”

    protoc.exe即将生成的.cc和.h文件配置到输出,否则protoc.exe无法正常运行并生成所需的文件。

image.png

demo代码

#include <string>
#include "message.pb.h"

int main() {
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  tutorial::Person john;
  john.set_name("hello word");
  john.set_id(998);
  tutorial::Person_PhoneNumber* ph1 = john.add_phones();
  ph1->set_number("111111");
  ph1->set_type(tutorial::Person_PhoneType_HOME);
  tutorial::Person_PhoneNumber* ph2 = john.add_phones();
  ph2->set_number("222222");
  ph2->set_type(tutorial::Person_PhoneType_MOBILE);

  std::string serialize;
  bool ret = john.SerializePartialToString(&serialize);

  tutorial::Person john2;
  ret = john2.ParseFromString(serialize);

  std::string name = john2.name();
  int32_t id = john2.id();
  for (auto& iter : john2.phones()) {
    std::string phone = iter.number();
    tutorial::Person_PhoneType type = iter.type();
    int a = 1;
  }

  std::string debug = john.DebugString();
  google::protobuf::ShutdownProtobufLibrary();
}
    文章作者:xuwenyan
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。

    扫描二维码推送至手机访问。

    版权声明:本文由艺文笔记发布,如需转载请注明出处。

    本文链接:https://www.xuwenyan.com/archives/2813

    分享给朋友:

    “c++如何编译和使用probuf” 的相关文章

    C++隐藏程序崩溃,让程序优雅的崩溃

    C++隐藏程序崩溃,让程序优雅的崩溃

    我们的程序并不能保证是完全稳定的,当程序崩溃时会展示一个崩溃提示框给用户,这给用户带来的感觉非常不友好。当我们的程序是一个服务程序时(没有ui界面),用户可能根本就感知不到这个程序的存在,这种情况下如果程序崩溃,在不显示崩溃提示的前提下,我们只需要将这个服务程序重启就可以了,这对用户来说可能会友好...

    C++如何实现窗口全屏显示

    C++如何实现窗口全屏显示

    窗口全屏,直接上代码:void FullScreen(HWND hwnd) {   //去掉所有边框,解决虚拟机win10任务栏显示问题   DWORD style = ::GetWindowLo...

    C++如何实现远程注入dll

    C++如何实现远程注入dll

    如何把我们的代码放到别人的进程里面运行?我们需要做一个dll动态库,然后使用远程注入技术,将我们的dll注入到别人的进程里面,然后加载起来。这样我们的代码就可以在别人的进程里面工作了。注入代码#include "stdafx.h" int EnableD...

    C++指针*为什么靠后会比较好?

    C++指针*为什么靠后会比较好?

    大多数书中和大神的代码里,往往指针的*都是靠变量而不是靠类型的,这主要是为了不造成我们第一眼对变量类型的误解和对指针类型的误解,比如: int* p1,p2 我们一眼看上去是不是通常会觉得p1、p1都是一个int*的指针呢?因为我们通常会误把int*当作一个类型,然而无论int*还是i...

    C++如何获取控制台程序的输出内容?

    C++如何获取控制台程序的输出内容?

    很多工具程序(如ffmpeg)的进度显示往往都是以控制台字符显示的方法,我们可能需要调用这种控制台工具去完成工作,但同时又希望以友好的ui界面去显示当前的工作状态(如进度)。此时我们能想到的就是运行控制台程序,然后以某种方式去获取到控制台程序的输出,然后转换到我们的ui界面上去显示。 有多种...

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    例如,我用VC2015的工程向导新建一个ATL的工程名字叫myAtl,那么VC会同时给我生成一个叫做myAtlPS的工程。这个myAtlPS工程是做什么的?什么情况下可以不需要它?什么情况下它又是必须存在的? PS工程是什么?可以不要吗? 这个PS工程叫做代理与存根(proxy&nbs...