2012-06-27 2 views
5

В общем, что я хочу, это какое-то время компиляции генерируется версия, которая связана с точным определением структуры. Если определение изменений структуры в любом случае (добавлено поле, переехал, может быть переименован), я хочу, чтобы версия изменить тоже.Создать идентификатор версии определения структуры?

Такая постоянная версия будет полезна при чтении ранее сериализации структуры, чтобы убедиться, что она по-прежнему совместимы. Альтернатива будет вручную отслеживание вручную указывается константа, которая имеет потенциально запутанные эффекты, если Инкрементирование забывается (десериализация производит мусор), а также поднимает вопрос, когда именно, чтобы увеличить его (в процессе разработки и тестирования, или только в каком-то выпуска).

Это может быть достигнут с помощью внешнего инструмента для создания хэша по определению структуры, но мне интересно, если это возможно с помощью компилятором C (и/или, возможно, его препроцессор) сам.

Это на самом деле какая-то форма самоанализа и поэтому я подозреваю, что это не может быть вообще возможно в ANSI C, но я был бы счастлив с решением, которое работает с GCC и лязгом.

ответ

2

API-интерфейс Windows, используется для (до сих пор делает?) Есть член размер, как один из первых членов структуры, так что он знал, какую версию структуры было быть принято (см 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.

+0

Любая ссылка на это МС? – ouah

+0

Добавлен пример –

+0

Спасибо. Я думал о просто использовании sizeof, но это, конечно, не защищает от перемещаемых полей или других операций, которые приводят к любому ранее увиденному размеру. Для Windows API, вероятно, хорошая идея ограничить модификацию только добавлений полей, но в настоящее время я действительно не хочу идти так далеко ... –

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; 
} 

Этот код prints

358944 478108 399864 597272 

Как вы можете видеть, этот код создает константы во время выполнения для каждой структуры, которая реагирует на изменение порядка полей различной длины и изменения полей. Он также реагирует на добавление полей, даже если вы забыли обновить список полей, на которых вы основываете свои вычисления, что должно создать какую-то систему безопасности.

+0

А, я забыл о 'offsetof'. Думаю, это самое близкое с ANSI C? –

+0

@Julien Да, я думаю, вы не можете сделать намного лучше, чем комбинировать эти два, по крайней мере, в ANSI C. Вы можете построить лучший 'COMBINE', хотя: мой выглядит как быстрая и грязная работа, хотя я использую что-то вроде что в производственном коде для хэширования различных структур. – dasblinkenlight

+0

@Julien Если у вас нет ограничения на то, что функция должна быть вычислена во время компиляции, вы можете потенциально защитить от переименования, вычислив хеш на строках, которые представляют имена полей структуры (вам нужно будет использовать оператор '#' препроцессора стробирования для этого). – dasblinkenlight

Смежные вопросы