Cで型安全可変長配列ライブラリをつくる
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して。
オリジナルは…どっかで見たような気もするし、見てないような気もする。ちょっと思い出せない。