2018/02/25

[c/c++]構造体のメンバのサイズだけ知りたい

検索すると、この手の情報はたくさん出てくるのだが、自分でやってみたら書いてみたくなっても仕方なかろう?


サイズをしらべると言えば、sizeof演算子だ。
ただ、これは構造体のメンバを直接指定することができない・・・というよりも、C言語として、構造体の型のメンバだけを表す方法が無いのだと思う。

01: struct aaa {
02:     uint8_t     item8;
03:     uint64_t    item64;
04:     const char* itemc;
05:     int16_t     item16;
06: };

こんな構造体があったとして、たとえばitem64だけを指す方法が無い。
インスタンスになってしまえばよいのだが、sizeofしたいだけなのインスタンスを作るのは避けたい。

じゃあどうするかというと、C言語としてインスタンスのように見えるものを使えばよい。
というわけで、適当な数字を「これはstruct aaa型のアドレスなんです!」と主張して、そのポインタのメンバをsizeofしてしまうわけだ。

#define M_SIZE(type, mem)   sizeof(((type *)0)->mem)

こんなマクロを作って、

M_SIZE(struct aaa, item64)

とすると、

sizeof(((struct aaa*)0)->item64)

と展開される。
意味としては、アドレス0にstruct aaa型のメモリが入っていると見なしているだけだ。
アドレスにアクセスするわけではないので、0じゃなくても、100でも1000でもよい。


急にこの話が出てきたのは、lmdbと関係している。

いま、構造体のデータをlmdbでがさっとメモリダンプ的に保存させているのだが、構造体の構成が変わるたびに前のDBが使えなくなってしまうので、そろそろ何とかしたいと考えている。

やるなら、各メンバごとにkey/dataで保存させていくしか無かろう。
無いのだが、書き直すのがめんどくさい。
なるべく多く書かずにやらせたいわけだ。


lmdbは、keyもdataもMDB_val型を使っている。
MDB_val型は、サイズとデータを持つ構造体だ。
keyにつける名前はバイナリでも文字列でも何でもよいのだが、構造体であればメンバ名にするのがよいだろう。
keyのサイズはstrlen()で出せるからよいとして、あとはdataのサイズだ。
これを機械的に出したいなら、上記のマクロのようなものを作ってしまうのがよかろう。

そして、key名もdataサイズもメンバ名で取り出せるなら、こんなものを用意するとよいか。

#define ARRAY_SIZE(a)       (sizeof(a) / sizeof(a[0]))
#define M_SIZE(type, mem)   sizeof(((type *)0)->mem)
#define M_ITEM(type, mem)   { #mem, M_SIZE(type, mem) }

struct aaa {
    uint8_t     item8;
    uint64_t    item64;
    const char* itemc;
    int16_t     item16;
};

const struct {
    const char  *name;
    size_t      sz;
} DB[] = {
    M_ITEM(struct aaa, item8),
    M_ITEM(struct aaa, item64),
    M_ITEM(struct aaa, itemc),
    M_ITEM(struct aaa, item16)
};


int main(void)
{
    for (int lp = 0; lp < ARRAY_SIZE(DB); lp++) {
        printf("name=%s: %lu\n", DB[lp].name, DB[lp].sz);
    }
}

まあ、そこまで悪くはないかな。

0 件のコメント:

コメントを投稿

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

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