外贸网站推广怎样做,聚名网app,网站建设需要具备,免费秒玩小游戏原文#xff1a;http://www.cnblogs.com/stephen-liu74/archive/2013/01/04/2842533.html 这篇Blog仍然是以Google的官方文档为主线#xff0c;代码实例则完全取自于我们正在开发的一个Demo项目#xff0c;通过前一段时间的尝试#xff0c;感觉这种结合的方式比较有利于培训… 原文http://www.cnblogs.com/stephen-liu74/archive/2013/01/04/2842533.html 这篇Blog仍然是以Google的官方文档为主线代码实例则完全取自于我们正在开发的一个Demo项目通过前一段时间的尝试感觉这种结合的方式比较有利于培训和内部的技术交流。还是那句话没有最好的只有最适合的。我想写Blog也是这一道理吧不同的技术主题可能需要采用不同的风格。好了还是让我们尽早切入主题吧。 一、生成目标语言代码。 下面的命令帮助我们将MyMessage.proto文件中定义的一组Protocol Buffer格式的消息编译成目标语言C的代码。至于消息的内容我们会在后面以分段的形式逐一列出同时也会在附件中给出所有源代码。 protoc -I./message --cpp_out./src ./MyMessage.proto 从上面的命令行参数中可以看出待编译的文件为MyMessage.proto他存放在当前目录的message子目录下。--cpp_out参数则指示编译工具我们需要生成目标语言是C输出目录是当前目录的src子目录。在本例中生成的目标代码文件名是MyMessage.pb.h和MyMessage.pb.cc。 二、简单message生成的C代码。 这里先定义一个最简单的message其中只是包含原始类型的字段。 option optimize_for LITE_RUNTIME; message LogonReqMessage { required int64 acctID 1; required string passwd 2; } 由于我们在MyMessage文件中定义选项optimize_for的值为LITE_RUNTIME因此由该.proto文件生成的所有C类的父类均为::google::protobuf::MessageLite而非::google::protobuf::Message。在上一篇博客中已经给出了一些简要的说明MessageLite类是Message的父类在MessageLite中将缺少Protocol Buffer对反射的支持而此类功能均在Message类中提供了具体的实现。对于我们的项目而言整个系统相对比较封闭不会和更多的外部程序进行交互与此同时我们的客户端部分又是运行在Android平台有鉴于此我们考虑使用LITE版本的Protocol Buffer。这样不仅可以得到更高编码效率而且生成代码编译后所占用的资源也会更少至于反射所能带来的灵活性和极易扩展性对于该项目而言完全可以忽略。下面我们来看一下由message LogonReqMessage生成的C类的部分声明以及常用方法的说明性注释。 1 class LogonReqMessage : public ::google::protobuf::MessageLite {2 public: 3 LogonReqMessage(); 4 virtual ~LogonReqMessage(); 5 6 // implements Message ---------------------------------------------- 7 //下面的成员函数均实现自MessageLite中的虚函数。 8 //创建一个新的LogonReqMessage对象等同于clone。 9 LogonReqMessage* New() const; 10 //用另外一个LogonReqMessage对象初始化当前对象等同于赋值操作符重载operator 11 void CopyFrom(const LogonReqMessage from); 12 //清空当前对象中的所有数据既将所有成员变量置为未初始化状态。 13 void Clear(); 14 //判断当前状态是否已经初始化。 15 bool IsInitialized() const; 16 //在给当前对象的所有变量赋值之后获取该对象序列化后所需要的字节数。 17 int ByteSize() const; 18 //获取当前对象的类型名称。 19 ::std::string GetTypeName() const; 20 21 // required int64 acctID 1; 22 //下面的成员函数都是因message中定义的acctID字段而生成。 23 //这个静态成员表示AcctID的标签值。命名规则是k FieldName(驼峰规则) FieldNumber。 24 static const int kAcctIDFieldNumber 1; 25 //如果acctID字段已经被设置返回true否则false。 26 inline bool has_acctid() const; 27 //执行该函数后has_acctid函数将返回false而下面的acctid函数则返回acctID的缺省值。 28 inline void clear_acctid(); 29 //返回acctid字段的当前值如果没有设置则返回int64类型的缺省值。 30 inline ::google::protobuf::int64 acctid() const; 31 //为acctid字段设置新值调用该函数后has_acctid函数将返回true。 32 inline void set_acctid(::google::protobuf::int64 value); 33 34 // required string passwd 2; 35 //下面的成员函数都是因message中定义的passwd字段而生成。这里生成的函数和上面acctid 36 //生成的那组函数基本相似。因此这里只是列出差异部分。 37 static const int kPasswdFieldNumber 2; 38 inline bool has_passwd() const; 39 inline void clear_passwd(); 40 inline const ::std::string passwd() const; 41 inline void set_passwd(const ::std::string value); 42 //对于字符串类型字段设置const char*类型的变量值。 43 inline void set_passwd(const char* value); 44 inline void set_passwd(const char* value, size_t size); 45 //可以通过返回值直接给passwd对象赋值。在调用该函数之后has_passwd将返回true。 46 inline ::std::string* mutable_passwd(); 47 //释放当前对象对passwd字段的所有权同时返回passwd字段对象指针。调用此函数之后passwd字段对象 48 //的所有权将移交给调用者。此后再调用has_passwd函数时将返回false。 49 inline ::std::string* release_passwd(); 50 private: 51 ... ... 52 }; 下面是读写LogonReqMessage对象的C测试代码和说明性注释。 1 void testSimpleMessage()2 {3 printf(This is simple message.\n); 4 //序列化LogonReqMessage对象到指定的内存区域。 5 LogonReqMessage logonReq; 6 logonReq.set_acctid(20); 7 logonReq.set_passwd(Hello World); 8 //提前获取对象序列化所占用的空间并进行一次性分配从而避免多次分配 9 //而造成的性能开销。通过该种方式还可以将序列化后的数据进行加密。 10 //之后再进行持久化或是发送到远端。 11 int length logonReq.ByteSize(); 12 char* buf new char[length]; 13 logonReq.SerializeToArray(buf,length); 14 //从内存中读取并反序列化LogonReqMessage对象同时将结果打印出来。 15 LogonReqMessage logonReq2; 16 logonReq2.ParseFromArray(buf,length); 17 printf(acctID %I64d, password %s\n,logonReq2.acctid(),logonReq2.passwd().c_str()); 18 delete [] buf; 19 } 三、嵌套message生成的C代码。 enum UserStatus { OFFLINE 0; ONLINE 1; } enum LoginResult { LOGON_RESULT_SUCCESS 0; LOGON_RESULT_NOTEXIST 1; LOGON_RESULT_ERROR_PASSWD 2; LOGON_RESULT_ALREADY_LOGON 3; LOGON_RESULT_SERVER_ERROR 4; } message UserInfo { required int64 acctID 1; required string name 2; required UserStatus status 3; } message LogonRespMessage { required LoginResult logonResult 1; required UserInfo userInfo 2; //这里嵌套了UserInfo消息。 } 对于上述消息生成的C代码UserInfo因为只是包含了原始类型字段因此和上例中的LogonReqMessage没有太多的差别这里也就不在重复列出了。由于LogonRespMessage消息中嵌套了UserInfo类型的字段在这里我们将仅仅给出该消息生成的C代码和关键性注释。 1 class LogonRespMessage : public ::google::protobuf::MessageLite {2 public: 3 LogonRespMessage(); 4 virtual ~LogonRespMessage(); 5 6 // implements Message ---------------------------------------------- 7 ... ... //这部分函数和之前的例子一样。 8 9 // required .LoginResult logonResult 1; 10 //下面的成员函数都是因message中定义的logonResult字段而生成。 11 //这一点和前面的例子基本相同只是类型换做了枚举类型LoginResult。 12 static const int kLogonResultFieldNumber 1; 13 inline bool has_logonresult() const; 14 inline void clear_logonresult(); 15 inline LoginResult logonresult() const; 16 inline void set_logonresult(LoginResult value); 17 18 // required .UserInfo userInfo 2; 19 //下面的成员函数都是因message中定义的UserInfo字段而生成。 20 //这里只是列出和非消息类型字段差异的部分。 21 static const int kUserInfoFieldNumber 2; 22 inline bool has_userinfo() const; 23 inline void clear_userinfo(); 24 inline const ::UserInfo userinfo() const; 25 //可以看到该类并没有生成用于设置和修改userInfo字段set_userinfo函数而是将该工作 26 //交给了下面的mutable_userinfo函数。因此每当调用函数之后Protocol Buffer都会认为 27 //该字段的值已经被设置了同时has_userinfo函数亦将返回true。在实际编码中我们可以 28 //通过该函数返回userInfo字段的内部指针并基于该指针完成userInfo成员变量的初始化工作。 29 inline ::UserInfo* mutable_userinfo(); 30 inline ::UserInfo* release_userinfo(); 31 private: 32 ... ... 33 }; 下面是读写LogonRespMessage对象的C测试代码和说明性注释。 1 void testNestedMessage()2 {3 printf(This is nested message.\n); 4 LogonRespMessage logonResp; 5 logonResp.set_logonresult(LOGON_RESULT_SUCCESS); 6 //如上所述通过mutable_userinfo函数返回userInfo字段的指针之后再初始化该对象指针。 7 UserInfo* userInfo logonResp.mutable_userinfo(); 8 userInfo-set_acctid(200); 9 userInfo-set_name(Tester); 10 userInfo-set_status(OFFLINE); 11 int length logonResp.ByteSize(); 12 char* buf new char[length]; 13 logonResp.SerializeToArray(buf,length); 14 15 LogonRespMessage logonResp2; 16 logonResp2.ParseFromArray(buf,length); 17 printf(LogonResult %d, UserInfo-acctID %I64d, UserInfo-name %s, UserInfo-status %d\n 18 ,logonResp2.logonresult(),logonResp2.userinfo().acctid(),logonResp2.userinfo().name().c_str(),logonResp2.userinfo().status()); 19 delete [] buf; 20 } 四、repeated嵌套message生成的C代码。 message BuddyInfo { required UserInfo userInfo 1; required int32 groupID 2; } message RetrieveBuddiesResp { required int32 buddiesCnt 1; repeated BuddyInfo buddiesInfo 2; } 对于上述消息生成的代码我们将只是针对RetrieveBuddiesResp消息所对应的C代码进行详细说明其余部分和前面小节的例子基本相同可直接参照。而对于RetrieveBuddiesResp类中的代码我们也仅仅是对buddiesInfo字段生成的代码进行更为详细的解释。 1 class RetrieveBuddiesResp : public ::google::protobuf::MessageLite {2 public: 3 RetrieveBuddiesResp(); 4 virtual ~RetrieveBuddiesResp(); 5 6 ... ... //其余代码的功能性注释均可参照前面的例子。 7 8 // repeated .BuddyInfo buddiesInfo 2; 9 static const int kBuddiesInfoFieldNumber 2; 10 //返回数组中成员的数量。 11 inline int buddiesinfo_size() const; 12 //清空数组中的所有已初始化成员调用该函数后buddiesinfo_size函数将返回0。 13 inline void clear_buddiesinfo(); 14 //返回数组中指定下标所包含元素的引用。 15 inline const ::BuddyInfo buddiesinfo(int index) const; 16 //返回数组中指定下标所包含元素的指针通过该方式可直接修改元素的值信息。 17 inline ::BuddyInfo* mutable_buddiesinfo(int index); 18 //像数组中添加一个新元素。返回值即为新增的元素可直接对其进行初始化。 19 inline ::BuddyInfo* add_buddiesinfo(); 20 //获取buddiesInfo字段所表示的容器该函数返回的容器仅用于遍历并读取不能直接修改。 21 inline const ::google::protobuf::RepeatedPtrField ::BuddyInfo 22 buddiesinfo() const; 23 //获取buddiesInfo字段所表示的容器指针该函数返回的容器指针可用于遍历和直接修改。 24 inline ::google::protobuf::RepeatedPtrField ::BuddyInfo * 25 mutable_buddiesinfo(); 26 private: 27 ... ... 28 }; 下面是读写RetrieveBuddiesResp对象的C测试代码和说明性注释。 1 void testRepeatedMessage()2 {3 printf(This is repeated message.\n); 4 RetrieveBuddiesResp retrieveResp; 5 retrieveResp.set_buddiescnt(2); 6 BuddyInfo* buddyInfo retrieveResp.add_buddiesinfo(); 7 buddyInfo-set_groupid(20); 8 UserInfo* userInfo buddyInfo-mutable_userinfo(); 9 userInfo-set_acctid(200); 10 userInfo-set_name(user1); 11 userInfo-set_status(OFFLINE); 12 13 buddyInfo retrieveResp.add_buddiesinfo(); 14 buddyInfo-set_groupid(21); 15 userInfo buddyInfo-mutable_userinfo(); 16 userInfo-set_acctid(201); 17 userInfo-set_name(user2); 18 userInfo-set_status(ONLINE); 19 20 int length retrieveResp.ByteSize(); 21 char* buf new char[length]; 22 retrieveResp.SerializeToArray(buf,length); 23 24 RetrieveBuddiesResp retrieveResp2; 25 retrieveResp2.ParseFromArray(buf,length); 26 printf(BuddiesCount %d\n,retrieveResp2.buddiescnt()); 27 printf(Repeated Size %d\n,retrieveResp2.buddiesinfo_size()); 28 //这里仅提供了通过容器迭代器的方式遍历数组元素的测试代码。 29 //事实上通过buddiesinfo_size和buddiesinfo函数亦可循环遍历。 30 RepeatedPtrFieldBuddyInfo* buddiesInfo retrieveResp2.mutable_buddiesinfo(); 31 RepeatedPtrFieldBuddyInfo::iterator it buddiesInfo-begin(); 32 for (; it ! buddiesInfo-end(); it) { 33 printf(BuddyInfo-groupID %d\n, it-groupid()); 34 printf(UserInfo-acctID %I64d, UserInfo-name %s, UserInfo-status %d\n 35 , it-userinfo().acctid(), it-userinfo().name().c_str(),it-userinfo().status()); 36 } 37 delete [] buf; 38 } 最后需要说明的是Protocol Buffer仍然提供了很多其它非常有用的功能特别是针对序列化的目的地比如文件流和网络流等。与此同时也提供了完整的官方文档和规范的命名规则在很多情况下可以直接通过函数的名字便可获悉函数所完成的工作。转载于:https://www.cnblogs.com/wnnily/p/5979817.html