У меня очень большая struct
в существующей программе. Эта структура включает в себя большое количество битовых полей.
Я хочу сохранить его часть (скажем, 10 полей из 150).
Пример кода, который я использовал бы для сохранения подкласса:
typedef struct {int a;int b;char c} bigstruct;
typedef struct {int a;char c;} smallstruct;
void substruct(smallstruct *s,bigstruct *b) {
s->a = b->a;
s->c = b->c;
}
int save_struct(bigstruct *bs) {
smallstruct s;
substruct(&s,bs);
save_struct(s);
}
Мне также хотелось бы, чтобы выбор какой-либо его части не был бы слишком сложным, поскольку я хочу менять это время от времени. Наивный подход, который я представил ранее, очень хрупок и недостижим. При масштабировании до 20 различных полей необходимо изменить поля как в smallstruct
, так и в функции substruct
.
Я подумал о двух лучших подходах. К сожалению, оба требуют, чтобы я использовал какой-то внешний CIL подобный инструмент для разбора моих структур.
Первый подход - автоматическое создание функции substruct
. Я просто установлю структуру smallstruct
, и у меня будет программа, которая будет анализировать ее и генерировать функцию substruct
в соответствии с полями в smallstruct
.
Второй подход - создание (с помощью C parser) метаинформации о bigstruct
, а затем написание библиотеки, которая позволила бы мне получить доступ к определенному полю в структуре. Это было бы как специальная реализация отражения классов Java.
Например, при условии отсутствия выравнивания структуры, для структуры
struct st {
int a;
char c1:5;
char c2:3;
long d;
}
Я сгенерирую следующую метаинформацию:
int field2distance[] = {0,sizeof(int),sizeof(int),sizeof(int)+sizeof(char)}
int field2size[] = {sizeof(int),1,1,sizeof(long)}
int field2bitmask[] = {0,0x1F,0xE0,0};
char *fieldNames[] = {"a","c1","c2","d"};
Я получу поле i
th с этой функцией:
long getFieldData(void *strct,int i) {
int distance = field2distance[i];
int size = field2size[i];
int bitmask = field2bitmask[i];
void *ptr = ((char *)strct + distance);
long result;
switch (size) {
case 1: //char
result = *(char*)ptr;
break;
case 2: //short
result = *(short*)ptr;
...
}
if (bitmask == 0) return result;
return (result & bitmask) >> num_of_trailing_zeros(bitmask);
}
Оба метода требуют дополнительной работы, но как только синтаксический анализатор находится в вашем make-файле - смена подструктуры становится легкой задачей.
Однако я бы предпочел сделать это без каких-либо внешних зависимостей.
У кого-нибудь есть идеи получше? Где мои идеи полезны, есть ли доступная реализация моих идей в Интернете?