Variant型をどう実装する?
C言語/C++では、厳密な型を持っていて、任意の型を取り扱う方法が言語レベルでは存在しない。
一方、JSON や YAML などでは任意のデータ型をやり取りするように設計されているため、アンマッチ状態になっている。
既存の実装
Windows の VARIANT 型(COM/OLE)(Windows 限定)
glib の GVariant
C++(C++17) の std::variant
既存の JSON, YAML などの実装の流用(JSON, YAML などの仕様に強く依存)
C++ なら std:variant が今後は正解か。
C言語/C++ では union による共用体があるので、型IDとの組み合わせで実装するのが一般的
code:c
typedef struct Variant {
int typeId; // どの型のデータなのかを保持
union {
int i;
long long ll;
double d;
char *s;
} value;
} Variant_t;
ただし、この方法は、value のデータサイズが必ず最大幅を取ってしまう。(long long ならせいぜい8バイトくらいだが。long double を入れると16バイトになる。)
C言語では構造体の前方の部分が一致していれば型変換してもよいことから、型ごとに構造体を用意する方法がある。
最近ではメモリが潤沢にあるので、そこまで気にしなくてもいいかもしれない。
組み込みシステムのようなメモリ量が厳しいところでは切り詰めるのは有効かもしれない。
この際、素直にオブジェクト方式にして、仮想関数テーブルへのポインタを持ってしまうのが一番合理的かもしれない。(COM はまさしくそういう仕組み)
そこまでしてC言語を使うか? という問題ではある。
code:c
// 概念なのでこのままでは動かない
typedef struct IUnknown IUnknown;
typedef struct IUnknown {
int queryInterface(void *pObj, const UUID uuid, IUnknown *pIUnknown);
int toString(char *p, size_t len);
};
typedef struct Object {
IUnknown *vtbl;
...
} Object_t;