2018/03/18

[c/c++]protobuf-c (5)

ようやく、本題のprotobuf-cだ。

https://github.com/protobuf-c/protobuf-c

protocへPATHを通しておく。

git clone https://github.com/protobuf-c/protobuf-c.git
cd protobuf-c
./configure

...

configure: error: required protobuf header file not found

怒られた。。。って、これは1回目と同じ話じゃないか。
C++のprotobufはローカルのディレクトリにインストールしたので、確かに探せないのは分かる。

こんな感じにすると、configureできた。
CFLAGSではダメで、CPPFLAGSを使うというのがポイントか。
また、インストール先はC++版と同じ場所にしておいた方がよさそうだ。

./configure --prefix=`pwd`/../../../cpplang/protobuf/install CPPFLAGS=-I`pwd`/../../../cpplang/protobuf/install/include LDFLAGS=-L`pwd`/../../../cpplang/protobuf/install/lib
make
make install


protocへPATHを通しているが、それはcpplang/protobuf/install/binに方になっている前提で話を進める。
protobuf-cでmake installしたときにバイナリがそこへコピーされるためだ。


まず、--c_outを試す。

mkdir c
protoc --c_out=./c/ addressbook.proto

pb-c.cとpb-c.hが生成されたが、もちろんC++版とは違う内容だ。

ヘッダの構造は、こういう感じだ。

image

アンダースコア2つでつないである。
先頭がアンダースコアなものは、structのタグ名だ。
特に使っていないようだから、最初からtypedefだけでもいい気はするが、まあよかろう。


ソースファイルは、こう。

image

見た目でstaticかどうか区別が付かないのだが、Functionは全部public、Variableは「__descriptor」とついているものがpublic constだ。


では、googleのサンプルと同じようなものを作っていこう。

https://github.com/protobuf-c/protobuf-c/wiki/Examples


01: #include <stdio.h>
02: #include <stdlib.h>
03: #include <string.h>
04: 
05: #include "addressbook.pb-c.h"
06: 
07: 
08: int main(int argc, char *argv[])
09: {
10:     Tutorial__AddressBook addrbook = TUTORIAL__ADDRESS_BOOK__INIT;
11:     uint8_t *buf;
12:     unsigned int len;
13: 
14:     addrbook.n_people = 1;
15:     addrbook.people = (Tutorial__Person **)malloc(sizeof(Tutorial__Person*) * addrbook.n_people);
16:     for (int lp = 0; lp < addrbook.n_people; lp++) {
17:         addrbook.people[lp] = (Tutorial__Person *)malloc(sizeof(Tutorial__Person));
18:         Tutorial__Person init = TUTORIAL__PERSON__INIT;
19:         *addrbook.people[lp] = init;
20:     }
21: 
22:     addrbook.people[0]->id = 1;
23:     addrbook.people[0]->name = "yoshio";
24:     addrbook.people[0]->email = "yoshio@mail.com";
25: 
26:     len = tutorial__address_book__get_packed_size(&addrbook);
27:     buf = (uint8_t *)malloc(len);
28:     tutorial__address_book__pack(&addrbook, buf);
29:     fprintf(stderr, "Writing %u serialized bytes\n", len);
30:     for (size_t lp = 0; lp < len; lp++) {
31:         printf("%02x ", buf[lp]);
32:     }
33:     printf("\n");
34: 
35:     for (int lp = 0; lp < addrbook.n_people; lp++) {
36:         free(addrbook.people[lp]);
37:     }
38:     free(buf);
39:     return 0;
40: }

$ gcc -o tst -I../install/include addressbook.pb-c.c write.c -L../install/lib -lprotobuf-c
$ LD_LIBRARY_PATH=../install/lib ./tst
Writing 29 serialized bytes
0a 1b 0a 06 79 6f 73 68 69 6f 10 01 1a 0f 79 6f 73 68 69 6f 40 6d 61 69 6c 2e 63 6f 6d

C++版のファイルと比較しよう。

image

おお、一致した。


やっぱりというかなんというか、動的なメモリ管理が面倒だ。
repeatedもそうだし、char*もだ。
phonesを入力しようとしたら、またそっちも同じようにmalloc/freeがいるので、さらに面倒になるのだ。


もう少しやってみるが、protobuf-cは後から導入するよりも、最初から使うつもりで考えていないと、大変そうだ。
例えば、最初はchar[20]みたいな配列で管理していたものが、後から置き換えてchar*による動的管理になると、解放漏れなんかやってしまいそうだ。

あるいは、シリアライズしたいときだけコピーする、という方法があるか。
shallow copyしてアドレスだけ渡してやれば済むし。
ただ、repeatedのrepeatedなんかが出てくると、やはりめんどうか。


実はメモリダンプで十分、というときもあるだろうが、まあ、まずは使い慣れないとね。
使える道具が少ないと、「金槌を持っている人はすべてが釘に見える」みたいなことになりかねん。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。