5

基本的に、構造体の正確な定義に関連付けられた、ある種のコンパイル時に生成されるバージョンが必要です。構造体の定義が何らかの形で変更された場合 (フィールドの追加、移動、名前の変更など)、そのバージョンも変更する必要があります。

このようなバージョン定数は、以前にシリアル化された構造体を読み取るときに、互換性があることを確認するのに役立ちます。別の方法は、手動で指定された定数を手動で追跡することです。これは、インクリメントを忘れた場合に混乱を招く可能性があり (デシリアライズするとガベージが生成されます)、正確にいつインクリメントするかという問題も生じます (開発およびテスト中、または何らかの種類の間のみ)。リリースの)。

これは、外部ツールを使用して構造体定義のハッシュを生成することで実現できますが、C コンパイラ (および/またはそのプリプロセッサ) 自体で可能かどうか疑問に思っています。

これは実際にはある種のイントロスペクションであるため、ANSI C ではまったく不可能であると思われますが、gcc と clang で動作するソリューションがあれば幸いです。

4

2 に答える 2

2

Windows API は、構造体の最初のメンバーの 1 つとして size メンバーを使用していました (まだありますか?)。これにより、渡された構造体のバージョンを認識していました (WNDCLASSEX例を参照)。

struct Foo
{
    size_t size;
    char *bar;
    char *baz;
    /* Other fields */
};

呼び出す前に、次を使用してサイズを設定しますsizeof

struct Foo f;

f.size = sizeof(struct Foo);
f.bar = strdup("hi");
f.baz = strdup("there");

somefunc(&f);

次にsomefunc、メンバーに基づいて、sizeそれが扱っている構造体のバージョンがわかります。sizeofは実行時ではなくコンパイル時に評価されるため、これにより ABI の後方互換性が可能になります。

于 2012-06-27T21:41:22.070 に答える
2

自動的にそれを行うものは何もありませんが、合理的に確実に動作するものを構築できsizeofますoffsetof。次に例を示します。

#include <stdio.h>
#include <stddef.h>

#define COMBINE2(a,b) ((a)*31+(b)*11)
#define COMBINE3(a,b,c) COMBINE2(COMBINE2(a,b),c)
#define COMBINE4(a,b,c,d) COMBINE2(COMBINE3(a,b,c),d)

typedef struct A {
    int a1;
    char a2;
    float a3;
} A;

typedef struct B {
    int b1;
    char b2;
    double b3;
} B;

typedef struct C {
    char c2;
    int c1;
    float c3;
} C;

typedef struct D {
    int d1;
    char d2;
    float d3;
    int forgotten[2];
} D;

int main(void) {
    size_t aSign = COMBINE4(sizeof(A), offsetof(A,a1), offsetof(A,a2), offsetof(A,a3));
    size_t bSign = COMBINE4(sizeof(B), offsetof(B,b1), offsetof(B,b2), offsetof(B,b3));
    size_t cSign = COMBINE4(sizeof(C), offsetof(C,c1), offsetof(C,c2), offsetof(C,c3));
    size_t dSign = COMBINE4(sizeof(D), offsetof(D,d1), offsetof(D,d2), offsetof(D,d3));
    printf("%ld %ld %ld %ld", aSign, bSign, cSign, dSign);
    return 0;
}

このコードは印刷します

358944 478108 399864 597272

ご覧のとおり、このコードは、異なる長さのフィールドの並べ替えやフィールドの型の変更に反応する各構造体の実行時定数を生成します。また、計算の基礎となるフィールドのリストを更新するのを忘れた場合でも、フィールドの追加に反応します。これにより、ある種のセーフティ ネットが生成されるはずです。

于 2012-06-27T22:00:09.107 に答える