2018/03/01

[c/c++]構造体のメンバの構造体のメンバのサイズを知るのはめんどうそうだ

前回と似ているが、さらにめんどうな話だ。

struct {
  struct {
    int aaa;
  } bbb;
} ccc;

こんな形になっているときの、aaaのサイズを知りたい。


まずは、前回と同じようなプログラムを書いてみよう。

01: #include <stdio.h>
02: #include <inttypes.h>
03: 
04: #define ARRAY_SIZE(a)       (sizeof(a) / sizeof(a[0]))
05: #define M_SIZE(type, mem)   sizeof(((type *)0)->mem)
06: #define M_ITEM(type, mem)   { #mem, M_SIZE(type, mem) }
07: 
08: struct aaa {
09:     uint8_t     item8;
10:     uint64_t    item64;
11:     const char* itemc;
12:     int16_t     item16;
13:     struct {
14:         uint8_t     item8;
15:         uint64_t    item64;
16:         const char* itemc;
17:         int16_t     item16;
18:     } itemst;
19: };
20: 
21: const struct {
22:     const char  *name;
23:     size_t      sz;
24: } DB[] = {
25:     M_ITEM(struct aaa, item8),
26:     M_ITEM(struct aaa, item64),
27:     M_ITEM(struct aaa, itemc),
28:     M_ITEM(struct aaa, item16),
29:     M_ITEM(struct aaa, itemst),
30: };
31: 
32: 
33: int main(void)
34: {
35:     for (int lp = 0; lp < ARRAY_SIZE(DB); lp++) {
36:         printf("name=%s: %lu\n", DB[lp].name, DB[lp].sz);
37:     }
38: }

うちの環境だと、こうなった。

name=item8: 1
name=item64: 8
name=itemc: 8
name=item16: 2
name=itemst: 32

これだと、構造体まるまるのサイズになっている。
もし構造体の構成を変更してしまったら、DBに保存しているデータと互換性が無くなってしまう(あ、ここではDBに構造体のデータをまるごと残すという目標でやってます)。


もし、構造体メンバに構造体がいたとしても何とかしたいなら、その中身もまたシリアライズしなくてはならない。
ああ、シリアライズ地獄だ。。。


ここまでくると、もうマクロとか実装だけで解決するのでは無く、前処理をして、現在の構造体を処理するデータやコードを自動生成してもらって、それを埋め込みたくなってくる。

これで思い出すのが、protobufだ。
ずいぶん前にちょっとだけ調べたことがあるけれども、あのときはプロトコルのエンコード/デコードをする手段として探していたので、データ保存として見ていなかった。

protobuf自体は、もともとシリアライズする何かだったはずだ。
バイナリのサイズが大きくなりそうだから避けていたけど、もうLinuxでしか動かさない前提になってきたし、そもそもDBを使う時点でそこそこのストレージを積めるくらいには大きなプラットフォームだろうから、とにかく一般的な方法で楽に安全に解決させたい。



そういうわけで、次回からはprotobufをあまり力を入れずに調べていこう。

0 件のコメント:

コメントを投稿

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

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