Create version identifier of structure definition?

Basically, I want this to be some kind of compilation-generated version related to the exact definition of the structure. If the definition of the structure is changed in any way (added field, relocation, possibly renamed), I also want this version to change too.

Such a version constant would be useful when reading in a previously serialized structure to make sure that it is still compatible. An alternative would be to manually track the manually specified constant, which potentially confuses the effects if the increment is forgotten (deserialization produces garbage), and also raises the question of when exactly to increase it (during development and testing or only during some type of release).

This can be achieved using an external tool to generate a hash for the definition of the structure, but I am wondering if this is possible using the C compiler (and / or, possibly, its preprocessor).

This is actually a certain form of introspection, so I suspect that this might not be possible at all in ANSI C, but I would be pleased with the solution that works with gcc and clang.

+5
source share
2 answers

The Windows API used for (so far?) Has a size member as one of the first members of the structure, so that it knows what version of the structure it is passing in (see WNDCLASSEXas an example):

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

And before you call, you set the size with sizeof:

struct Foo f;

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

somefunc(&f);

somefunc , size, , . sizeof , , ABI .

+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

, , . , , , - .

+2

All Articles