一般に、C++ または C では、使用しているポインターの型を知る方法がありません。
この問題を解決する通常の方法は、ポインターが構造体を指すようにし、構造体内の既知の位置にデータの型を示すようにすることです。通常、既知の位置は構造体の最初の位置です。
例:
// signature value; use any value unlikely to happen by chance
#define VAR_SIG 0x11223344
typedef enum
{
vartypeInvalid = 0,
vartypeInt,
vartypeFloat,
vartypeDouble,
vartypeString,
vartypeMax // not a valid vartype
} VARTYPE;
typedef struct
{
VARTYPE type;
#ifdef DEBUG
uint32_t sig;
#endif // DEBUG
union data
{
int i;
float f;
double d;
char *s;
};
} VAR;
その後、サニティ チェックを実行できます。type
フィールドの値がより大きいかvartypeInvalid
小さいvartypeMax
かを確認できます (サニティ チェック コードでこれらの名前を編集する必要はありません。さらにタイプを追加する場合は、前vartypeMax
にそれらを追加します。リスト)。また、DEBUG
ビルドの場合、署名フィールドsig
に特定の署名値が含まれていることを確認できます。(これは、インスタンスを初期化するための初期化コードがVAR
常にsig
フィールドを設定する必要があることを意味します。)
このようなことを行う場合、どのように初期化しますか? ランタイム コードは常に機能します。
VAR v;
#ifdef DEBUG
v.sig = VAR_SIG;
#endif // DEBUG
v.type = vartypeFloat;
v.data = 3.14f;
コンパイル時に初期化したい場合はどうしますか? int
型は の最初の型であるため、整数値で初期化するのは簡単ですunion
。
VAR v =
{
vartypeInt,
#ifdef DEBUG
VAR_SIG,
#endif // DEBUG
1234
};
C99 準拠バージョンの C を使用している場合は、実際に構造体をフィールド名で初期化し、任意の型を割り当てることができます。float
しかし、Microsoft C は C99 に準拠していないため、構造体をordouble
値で初期化したい場合、上記は悪夢です。(float 値を整数にキャストすると、C は型を変更するだけでなく、値を丸めます。また、32 ビットを正しく表す 32 ビット整数値を移植可能に取得するためのトリックは私が知っているものではありません。 C プログラムではコンパイル時に float になります。)
コンパイル時のフロート パッキング/パニング
ただし、ポインターを使用している場合は簡単です。ユニオンの最初のフィールド名をポインター型にし、ポインターをキャストして、void *
上記のように構造体を初期化します (ポインターは1234
上記の場所に移動します)。
他の誰かのコードで書かれたテーブルを読んでいて、型識別子フィールドを追加する方法がない場合、私には一般的な答えはありません。ポインターをさまざまなタイプとして読み込んで、どれが機能するかを確認できると思いますか?