欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文讀懂C++中Protobuf

 更新時(shí)間:2023年05月17日 15:43:51   作者:令狐少俠、  
Protocol Buffers 是一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲格式,可以用于結(jié)構(gòu)化數(shù)據(jù)串行化、或者說序列化,本文詳解了Protobuf的使用,具有一定的參考價(jià)值,感興趣的可以了解一下

簡介

Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內(nèi)部的混合語言數(shù)據(jù)標(biāo)準(zhǔn),目前已經(jīng)正在使用的有超過 48,162 種報(bào)文格式定義和超過 12,183 個(gè) .proto 文件。他們用于 RPC 系統(tǒng)和持續(xù)數(shù)據(jù)存儲系統(tǒng)。

Protocol Buffers 是一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲格式,可以用于結(jié)構(gòu)化數(shù)據(jù)串行化、或者說序列化。它很適合做數(shù)據(jù)存儲或RPC數(shù)據(jù)交換格式??梢杂糜诩磿r(shí)通訊、數(shù)據(jù)存儲等領(lǐng)域的語言無關(guān)、平臺無關(guān)、可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)格式

Google的Protobuf了,相比于它的前輩xml、json,它的體量更小,解析速度更快,所以在 IM 這種通信應(yīng)用中,非常適合將 Protobuf 作為數(shù)據(jù)傳輸格式。
protobuf的核心內(nèi)容包括:

  • 定義消息:消息的結(jié)構(gòu)體,以message標(biāo)識。
  • 定義接口:接口路徑和參數(shù),以service標(biāo)識。

通過protobuf提供的機(jī)制,服務(wù)端與服務(wù)端之間只需要關(guān)注接口方法名(service)和參數(shù)(message)即可通信,而不需關(guān)注繁瑣的鏈路協(xié)議和字段解析,極大降低了服務(wù)端的設(shè)計(jì)開發(fā)成本。

查看版本

protoc --version    //查看版本

proto3 與 proto2 的區(qū)別

proto3 比 proto2 支持更多語言但 更簡潔。去掉了一些復(fù)雜的語法和特性,更強(qiáng)調(diào)約定而弱化語法

  • 在第一行非空白非注釋行,必須寫:syntax = “proto3”;
  • 字段規(guī)則移除了 “required”,并把 “optional” 改名為 “singular”;
  • proto3 repeated標(biāo)量數(shù)值類型默認(rèn)packed,而proto2默認(rèn)不開啟
    • 在 proto2 中,需要明確使用 [packed=true] 來為字段指定比較緊湊的 packed 編碼方式
  • 語言增加 Go、Ruby、JavaNano 支持;
  • proto2可以選填default,而proto3只能使用系統(tǒng)默認(rèn)的
    • 在 proto2 中,可以使用 default 選項(xiàng)為某一字段指定默認(rèn)值。在 proto3 中,字段的默認(rèn)值只能根據(jù)字段類型由系統(tǒng)決定。也就是說,默認(rèn)值全部是約定好的,而不再提供指定默認(rèn)值的語法
  • proto3必須有一個(gè)零值,以便我們可以使用 0 作為數(shù)字默認(rèn)值。零值需要是第一個(gè)元素,以便與proto2語義兼容,其中第一個(gè)枚舉值始終是默認(rèn)值。proto2則沒有這項(xiàng)要求。
  • roto3在3.5版本之前會丟棄未知字段。但在 3.5 版本中,重新引入了未知字段的保留以匹配 proto2 行為。在 3.5 及更高版本中,未知字段在解析過程中保留并包含在序列化輸出中
  • proto3移除了proto2的擴(kuò)展,新增了Any(仍在開發(fā)中)和JSON映射

定義數(shù)據(jù)結(jié)構(gòu)

syntax = "proto3";
message Person {
? ? string name = 1;
? ? int32 id = 2;
? ? string email = 3;
}

字段類型

Protobuf定義了一套基本數(shù)據(jù)類型

proto文件消息類型C++ 類型說明
doubledouble雙精度浮點(diǎn)型
floatfloat單精度浮點(diǎn)型
int32int32使用可變長編碼方式,負(fù)數(shù)時(shí)不夠高效,應(yīng)該使用sint32
int64int64使用可變長編碼方式,負(fù)數(shù)時(shí)不夠高效,應(yīng)該使用sint32
unit32unit32使用可變長編碼方式
unit64unit64使用可變長編碼方式
sint32int32使用可變長編碼方式,有符號的整型值,負(fù)數(shù)編碼時(shí)比通常的int32高效
sint64sint64使用可變長編碼方式,有符號的整型值,負(fù)數(shù)編碼時(shí)比通常的int64
fixed32unit32總是4個(gè)字節(jié),如果數(shù)值總是比2^28大的話,這個(gè)類型會比uint32高效
fixed64unit64總是8個(gè)字節(jié),如果數(shù)值總是比2^56大的話,這個(gè)類型會比uint64高效
sfixed32int32總是4個(gè)字節(jié)
sfixed64int64總是8個(gè)字節(jié)
boolbool布爾類型
stringstring一個(gè)字符串必須是utf-8編碼或者7-bit的ascii編碼的文本
bytesstring可能包含任意順序的字節(jié)數(shù)據(jù)

字段編號

消息定義中的每個(gè)字段都有一個(gè)唯一的編號。這些字段編號用于以二進(jìn)制格式標(biāo)識您的字段,一旦您的消息類型被使用,就不應(yīng)該被更改。

Tag的取值范圍最小是1,最大是229229-1,但但 19000~19999 是 protobuf 預(yù)留的,用戶不能使用。

雖然 編號的定義范圍比較大,但不同 編號也會對 protobuf 編碼帶來一些影響:

  • 1 ~ 15:單字節(jié)編碼
  • 16 ~ 2047:雙字節(jié)編碼

使用頻率高的變量最好設(shè)置為1~15,這樣可以減少編碼后的數(shù)據(jù)大小,但由于編號一旦指定不能修改,所以為了以后擴(kuò)展,也記得為未來保留一些 1~15 的 編號

字段規(guī)則

  • singular: 可以有零個(gè)或其中一個(gè)字段(但不超過一個(gè))。
  • repeated: 該字段可以重復(fù)任意次數(shù)(包括零次)。重復(fù)值的順序?qū)⒈槐A簟?/li>

在proto 3中,可擴(kuò)展的repeated字段為數(shù)字類型的默認(rèn)編碼。

在proto2中,規(guī)則為:

  • required:必須有一個(gè)
  • optional:0或者1個(gè)
  • repeated:任意數(shù)量(包括0)

添加更多消息類型

可以在單個(gè).proto中定義多種消息類型。如果您要定義多個(gè)相關(guān)消息,這很有用——例如,如果您想定義與搜索響應(yīng)消息類型相對應(yīng)的回復(fù)消息格式,可以將其添加到該.proto中:

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}
message SearchResponse {
 ...
}

添加注釋

proto 添加注釋,使用 C/C++風(fēng)格的 // 或者 /* … */ 語法.

保留字段

如果通過完全刪除某個(gè)字段或?qū)ζ溥M(jìn)行注釋來更新消息類型,將來的用戶可以在對該類型進(jìn)行自己的更新時(shí)重用該字段編號。如果他們以后加載舊版本的相同.proto文件,這可能會導(dǎo)致嚴(yán)重的問題 ,包括數(shù)據(jù)損壞、隱私漏洞等。
可以把它的變量名或 字段編號 用 reserved 標(biāo)注,這樣,當(dāng)這個(gè) Tag 或者變量名字被重新使用的時(shí)候,編譯器會報(bào)錯

message Foo {
    // 注意,同一個(gè) reserved 語句不能同時(shí)包含變量名和 Tag 
    reserved 2, 15, 9 to 11;
    reserved "foo", "bar";
}

默認(rèn)值

當(dāng)解析 message 時(shí),如果被編碼的 message 里沒有包含某些變量,那么根據(jù)類型不同,他們會有不同的默認(rèn)值:

  • string:默認(rèn)是空的字符串
  • byte:默認(rèn)是空的bytes
  • bool:默認(rèn)為false
  • numeric:默認(rèn)為0
  • enums:定義在第一位的枚舉值,也就是0
  • messages:根據(jù)生成的不同語言有不同的表現(xiàn)

收到數(shù)據(jù)后反序列化后,對于標(biāo)準(zhǔn)值類型的數(shù)據(jù),比如bool,如果它的值是 false,那么我們無法判斷這個(gè)值是對方設(shè)置的,還是對方壓根就沒給這個(gè)變量設(shè)置值。

定義枚舉

在 protobuf 中,我們也可以定義枚舉,并且使用該枚舉類型,比如:

message SearchRequest {
    string query = 1;
    int32 page_number = 2; // Which page number do we want
    int32 result_per_page = 3; // Number of results to return per page
    enum Corpus {
        UNIVERSAL = 0;
        WEB = 1;
        IMAGES = 2;
        LOCAL = 3;
        NEWS = 4;
        PRODUCTS = 5;
        VIDEO = 6;
    }
    Corpus corpus = 4;
}

枚舉定義在一個(gè)消息內(nèi)部或消息外部都是可以的,如果枚舉是 定義在 message 內(nèi)部,而其他 message 又想使用,那么可以通過 MessageType.EnumType 的方式引用。定義枚舉的時(shí)候,我們要保證第一個(gè)枚舉值必須是0,枚舉值不能重復(fù),除非使用 option allow_alias = true 選項(xiàng)來開啟別名。如:

enum EnumAllowingAlias {
    option allow_alias = true;
    UNKNOWN = 0;
    STARTED = 1;
    RUNNING = 1;
}

枚舉值的范圍是32-bit integer,但因?yàn)槊杜e值使用變長編碼,所以不推薦使用負(fù)數(shù)作為枚舉值,因?yàn)檫@會帶來效率問題

編譯.proto 文件

在.proto 文件中定義了數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)是面向開發(fā)者和業(yè)務(wù)程序的,并不面向存儲和傳輸。當(dāng)需要把這些數(shù)據(jù)進(jìn)行存儲或傳輸時(shí),就需要將這些結(jié)構(gòu)數(shù)據(jù)進(jìn)行序列化、反序列化以及讀寫。ProtoBuf 提供相應(yīng)的接口代碼,可以通過 protoc 這個(gè)編譯器來生成相應(yīng)的接口代碼,命令如下:

protoc編譯

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto
# $SRC_DIR: .proto 所在的源目錄
# --cpp_out: 生成 c++ 代碼
# $DST_DIR: 生成代碼的目標(biāo)目錄
# xxx.proto: 要針對哪個(gè) proto 文件生成接口代碼

cmake編譯

protobuf_generate_cpp

find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
# pb.cc文件路徑 pb.h文件路徑
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS person.proto)

有兩個(gè)缺點(diǎn):

  • 要求protobuf_generate_cpp命令和生成add_executable() 或 add_library() 的命令必須在同一個(gè)CMakeList中.
  • 無法設(shè)置源碼的生成路徑,只能默認(rèn)在相應(yīng)的build中生成

execute_process

以使用cmake中的execute_process命令調(diào)用protoc程序來自定義生成源碼的路徑

find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
execute_process(COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} -I=${PROJECT_SOURCE_DIR}/proto/ --cpp_out=${PROJECT_SOURCE_DIR}/  ${PROJECT_SOURCE_DIR}/proto/xxx.proto)
add_executable(file main.cpp ${PROJECT_SOURCE_DIR}/xxx.pb.cc file.cpp)

這種方法仍然存在缺點(diǎn):每次執(zhí)行cmake后,都會重新生成proto源碼,導(dǎo)致make時(shí)會因?yàn)樵创a變動(內(nèi)容未變,只是重新生成)而重新編譯程序

示例1:定義proto

定義proto

syntax = "proto3";
// 聲明是為了防止不同項(xiàng)目之間的命名沖突,編譯生成的類將被放置在一個(gè)與 package 名相同的命名空間中。
package tutorial;
message Student {
?? ?// 字段編號:消息定義中的每個(gè)字段都有一個(gè)唯一的編號。這些字段編號用于以二進(jìn)制格式標(biāo)識您的字段,一旦您的消息類型被使用,就不應(yīng)該被更改
?? ?uint64 id = 1;
?? ?string name = 2;
? ? // singular修飾符修飾的字段可以是0次或者1次。但是當(dāng)定制協(xié)議,用該修飾符修飾的字段都報(bào)錯
?? ?// singular string email = 3;
?? ?string email = 3;
?? ?enum PhoneType {
?? ??? ?MOBILE ?? ?= 0; //proto3版本中,首成員必須為0,成員不應(yīng)有相同的值
?? ??? ?HOME ?? ?= 1;
?? ?}
?? ?message PhoneNumber {?
?? ??? ?string number ?? ?= 1;
?? ? ? ?PhoneType type = 2;
?? ?}
?? ?// repeated: 該字段可以重復(fù)任意次數(shù)(包括零次)。重復(fù)值的順序?qū)⒈槐A?
?? ?repeated PhoneNumber phone = 4;
}

Protobuf API

看看讀寫類,編譯器為每個(gè)字段生成讀寫函數(shù)

? // optional uint64 id = 1;
? void clear_id();
? static const int kIdFieldNumber = 1;
? ::google::protobuf::uint64 id() const;
? void set_id(::google::protobuf::uint64 value);
? // optional string name = 2;
? void clear_name();
? static const int kNameFieldNumber = 2;
? const ::std::string& name() const;
? void set_name(const ::std::string& value);
? void set_name(const char* value);
? void set_name(const char* value, size_t size);
? ::std::string* mutable_name();
? ::std::string* release_name();
? void set_allocated_name(::std::string* name);
? // optional string email = 3;
? void clear_email();
? static const int kEmailFieldNumber = 3;
? const ::std::string& email() const;
? void set_email(const ::std::string& value);
? void set_email(const char* value);
? void set_email(const char* value, size_t size);
? ::std::string* mutable_email();
? ::std::string* release_email();
? void set_allocated_email(::std::string* email);
? // repeated .tutorial.Student.PhoneNumber phone = 4;
? int phone_size() const;
? void clear_phone();
? static const int kPhoneFieldNumber = 4;
? const ::tutorial::Student_PhoneNumber& phone(int index) const;
? ::tutorial::Student_PhoneNumber* mutable_phone(int index);
? ::tutorial::Student_PhoneNumber* add_phone();
? ::google::protobuf::RepeatedPtrField< ::tutorial::Student_PhoneNumber >*
? ? ? mutable_phone();
? const ::google::protobuf::RepeatedPtrField< ::tutorial::Student_PhoneNumber >&
? ? ? phone() const;

基本函數(shù):

  • set_*函數(shù):設(shè)置字段值
  • clear_*函數(shù):用來將字段重置到空狀態(tài)

數(shù)值類型的字段 id 就只有基本讀寫函數(shù),string類型的name和email有額外的函數(shù):

  • mutable_*函數(shù):數(shù)返回 string 的直接指針

重復(fù)的字段也有一些特殊的函數(shù)——如果你看一下重復(fù)字段 phone 的那些函數(shù),就會發(fā)現(xiàn)你可以:

  • 得到重復(fù)字段的 _size(Person 關(guān)聯(lián)了多少個(gè)電話號碼)。
  • 通過索引(index)來獲取一個(gè)指定的電話號碼。
  • mutable_phone函數(shù):通過指定的索引(index)來更新一個(gè)已經(jīng)存在的電話號碼。
  • add_phone函數(shù):向消息(message)中添加另一個(gè)電話號碼

標(biāo)準(zhǔn)消息函數(shù)

  void CopyFrom(const Student& from);
  void MergeFrom(const Student& from);
  void Clear();
  bool IsInitialized() const;

序列化和反序列化

bool SerializeToString(string* output) const; //將消息序列化并儲存在指定的string中。注意里面的內(nèi)容是二進(jìn)制的,而不是文本;我們只是使用string作為一個(gè)很方便的容器。
bool ParseFromString(const string& data); //從給定的string解析消息。
bool SerializeToArray(void * data, int size) const?? ?//將消息序列化至數(shù)組
bool ParseFromArray(const void * data, int size)?? ?//從數(shù)組解析消息
bool SerializeToOstream(ostream* output) const; //將消息寫入到給定的C++ ostream中。
bool ParseFromIstream(istream* input); //從給定的C++ istream解析消息。

實(shí)例2:proto文件讀寫

下面演示一個(gè)簡單例子,讀寫函數(shù)已經(jīng)封裝好了,大家可以自行調(diào)用!

config.conf:

pfe_file: "pfe.trt"
rpn_file: "rpn.trt"

pointpillars_config.proto:

syntax = "proto3";
message PointPillarsConfig {
? string pfe_file = 1;
? string rpn_file = 2;
}

main.cpp

#include <iostream>
#include <string>
#include "config.pb.h"
#include "file.h"
bool SetProtoToASCIIFile(const google::protobuf::Message &message,
? ? ? ? ? ? ? ? ? ? ? ? ?int file_descriptor) {
? using google::protobuf::TextFormat;
? using google::protobuf::io::FileOutputStream;
? using google::protobuf::io::ZeroCopyOutputStream;
? if (file_descriptor < 0) {
? ? std::cout << "Invalid file descriptor.";
? ? return false;
? }
? ZeroCopyOutputStream *output = new FileOutputStream(file_descriptor);
? bool success = TextFormat::Print(message, output);
? delete output;
? close(file_descriptor);
? return success;
}
bool GetProtoFromASCIIFile(const std::string& file_name,
? ? google::protobuf::Message* message) {
? ? using google::protobuf::TextFormat;
? ? using google::protobuf::io::FileInputStream;
? ? using google::protobuf::io::ZeroCopyInputStream;
? ? int file_descriptor = open(file_name.c_str(), O_RDONLY);
? ? if (file_descriptor < 0) {
? ? ? ? std::cout << "Failed to open file " << file_name << " in text mode.";
? ? ? ? // Failed to open;
? ? ? ? return false;
? ? }
? ? ZeroCopyInputStream* input = new FileInputStream(file_descriptor);
? ? bool success = TextFormat::Parse(input, message);
? ? if (!success) {
? ? ? ? std::cout << "Failed to parse file " << file_name << " as text proto.";
? ? }
? ? delete input;
? ? close(file_descriptor);
? ? return success;
}
int main(int argc, char *argv[])
{
? ? // 將此宏放在main函數(shù)中(使用 protobuf 庫之前的某個(gè)位置), 以驗(yàn)證您鏈接的版本是否與您編譯的頭文件匹配。 如果檢測到版本不匹配,該過程將中止
? ? GOOGLE_PROTOBUF_VERIFY_VERSION;
? ? PointPillarsConfig config;
? ? std::string config_file = "../config/pointpillars.conf";
? ? GetProtoFromFile(config_file, &config);
? ? std::cout << config.pfe_file() << std::endl;
? ? google::protobuf::ShutdownProtobufLibrary();
}

CMakeLists.txt:

CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
project(file)
find_package(Protobuf REQUIRED)
include_directories(
? ? ${Protobuf_INCLUDE_DIRS}
? ? ${GLOB_INCLUDE_DIRS}
? ? ${CMAKE_CURRENT_BINARY_DIR}
)
# protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS proto/pointpillars_config.proto)
# add_executable(file main.cpp ${PROTO_SRCS} file.cpp)
execute_process(COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} -I=${PROJECT_SOURCE_DIR}/proto/ --cpp_out=${PROJECT_SOURCE_DIR}/ ?${PROJECT_SOURCE_DIR}/proto/pointpillars_config.proto)
add_executable(file main.cpp ${PROJECT_SOURCE_DIR}/pointpillars_config.pb.cc file.cpp)
target_link_libraries(file ${Protobuf_LIBRARIES} )

上面是從文件讀數(shù)據(jù)寫入proto,SetProtoToASCIIFile為把proto數(shù)據(jù)寫入文件的函數(shù),大家可以自行調(diào)用

參考資料

官方文檔:https://developers.google.com/protocol-buffers/docs/reference/overview

到此這篇關(guān)于一文讀懂C++中Protobuf的文章就介紹到這了,更多相關(guān)C++ Protobuf內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言中數(shù)據(jù)的存儲詳解

    C語言中數(shù)據(jù)的存儲詳解

    這篇文章主要為大家介紹了C語言中數(shù)據(jù)的存儲,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助,希望能夠給你帶來幫助
    2021-11-11
  • C++遞歸線性陣列搜索數(shù)字的方法

    C++遞歸線性陣列搜索數(shù)字的方法

    這篇文章主要介紹了C++遞歸線性陣列搜索數(shù)字的方法,涉及C++遞歸及數(shù)組操作的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • 十分鐘學(xué)會C++?Traits

    十分鐘學(xué)會C++?Traits

    本文試圖以最簡潔的方式闡述對C++?traits?的理解,當(dāng)你理解了第二個(gè)例子的時(shí)候,相信你已經(jīng)理解了C++?traits,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-02-02
  • C++日歷拼圖的解法你了解嗎

    C++日歷拼圖的解法你了解嗎

    這篇文章主要為大家詳細(xì)介紹了日歷拼圖C++的解法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • 用C++實(shí)現(xiàn)推箱子小游戲

    用C++實(shí)現(xiàn)推箱子小游戲

    這篇文章主要為大家詳細(xì)介紹了用C++實(shí)現(xiàn)推箱子小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • C語言數(shù)據(jù)結(jié)構(gòu)之單鏈表的實(shí)現(xiàn)

    C語言數(shù)據(jù)結(jié)構(gòu)之單鏈表的實(shí)現(xiàn)

    鏈表是一種物理存儲結(jié)構(gòu)上非連續(xù)、非順序的存儲結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的。本文將用C語言實(shí)現(xiàn)單鏈表,需要的可以參考一下
    2022-06-06
  • C語言中大小寫字母相互轉(zhuǎn)化的方法示例

    C語言中大小寫字母相互轉(zhuǎn)化的方法示例

    在C語言中,大小寫字母的轉(zhuǎn)換可以通過標(biāo)準(zhǔn)庫中的ctype.h頭文件提供的函數(shù)來實(shí)現(xiàn),具體來說,toupper()函數(shù)可以將小寫字母轉(zhuǎn)換為大寫字母,而tolower()函數(shù)可以將大寫字母轉(zhuǎn)換為小寫字母,本文給大家介紹了C語言中大小寫字母相互轉(zhuǎn)化的方法,需要的朋友可以參考下
    2024-08-08
  • C語言實(shí)現(xiàn)會員計(jì)費(fèi)系統(tǒng)

    C語言實(shí)現(xiàn)會員計(jì)費(fèi)系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)會員計(jì)費(fèi)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C語言設(shè)計(jì)圖書登記系統(tǒng)與停車場管理系統(tǒng)的實(shí)例分享

    C語言設(shè)計(jì)圖書登記系統(tǒng)與停車場管理系統(tǒng)的實(shí)例分享

    這篇文章主要介紹了C語言設(shè)計(jì)圖書登記系統(tǒng)與停車場管理系統(tǒng)的實(shí)例分享,重在以最簡單的一些需求來展示管理系統(tǒng)的設(shè)計(jì)思路,需要的朋友可以參考下
    2016-06-06
  • 一文秒懂C語言/C++內(nèi)存管理(推薦)

    一文秒懂C語言/C++內(nèi)存管理(推薦)

    在C++中,內(nèi)存分為:棧、堆、自由存儲區(qū)、全局/靜態(tài)存儲區(qū)、常量存儲區(qū)。這篇文章主要介紹了一文秒懂C語言/C++內(nèi)存管理,需要的朋友可以參考下
    2020-11-11

最新評論