Cで汎用ライブラリをつくってると、void*の嵐になって型安全が無くなると思う。

ちょっとした手間で、それをなんとかする話。

struct varray { int nelem; void *values; }; #define VSET( t, a, i, e ) (((t*)a##t.values)[i] = e) #define VDECL( t, name ) struct varray name##t

こんなふうにして。

int main() { VDECL( int, a ); VSET( int, a, 0, 4 ); }

こんなふうにする。

変数宣言がちょっとキモくなるのと、配列アクセスが、キモくなる。のと、配列アクセスするときに型の名前がいる。

のだけど、

int main() { VDECL( int, a ); VSET( float, a, 0, 4.0 ); }

こういうのをコンパイルエラーにできる。原理は…名前のあとに型の名前をつけてるだけという。（なので、若干気にしないといけない。型に括弧付けてはいけないとか）

$ cat varray.c struct varray { int nelem; void *values; }; #define VSET( t, a, i, e ) (((t*)a##t.values)[i] = e) #define VDECL( t, name ) struct varray name##t struct nanika { VDECL( int, a ); }; int main() { struct nanika n; VDECL( int, a ); VSET( int, a, 0, 4 ); VSET( int, n.a, 0, 4 ); } $ gcc -E varray.c # 1 "varray.c" # 1 "<built-in>" # 1 "<コマンドライン>" # 1 "varray.c" struct varray { int nelem; void *values; }; struct nanika { struct varray aint; }; int main() { struct nanika n; struct varray aint; (((int*)aint.values)[0] = 4); (((int*)n.aint.values)[0] = 4); }

struct とかポインタとかはtypedefして。

オリジナルは…どっかで見たような気もするし、見てないような気もする。ちょっと思い出せない。

あと、配列ライブラリというと、gccのvecとかもおすすめ。(gcc/vec.h)