получение substruct из большой структуры в C

голоса
3

У меня очень большой 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 парсер) мета-информацию о bigstruct, а затем написать библиотеку , которая позволит мне получить доступ к конкретной области в структуры. Это было бы как одноранговой реализация класса отражения Java.

Например, предполагая отсутствие STRUCT-выравнивания, для структуры

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е поля с помощью этой функции:

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

Оба метода требует дополнительной работы, но после того, как анализатор в вашем Makefile - изменение substruct является ветер.

Однако я предпочел бы сделать это без каких-либо внешних зависимостей.

Кто-нибудь есть идея получше? Где мои идеи ничего хорошее, есть некоторая воевавшая реализация моих идей в Интернете?

Задан 19/05/2009 в 12:59
источник пользователем
На других языках...                            


5 ответов

голоса
3

Если изменить порядок полей не может быть и речи, вы можете изменить поля bigstruct таким образом, чтобы smallstruct поля вместе, а потом его просто вопрос литья от одного к другому (возможно добавление смещения) , Что-то вроде:

typedef struct {int a;char c;int b;} bigstruct;
typedef struct {int a;char c;} smallstruct;

int save_struct(bigstruct *bs) {
    save_struct((smallstruct *)bs);
}
Ответил 19/05/2009 в 13:11
источник пользователем

голоса
1

Макросы ваш друг.

Одним из решений было бы переместить большую-структуру из в своем собственном заголовочный файл, а затем макро партии.

Вместо того, чтобы определить структуру, как правило, приходят с выбором макросов, таких как BEGIN_STRUCTURE, END_STRUCTURE, NORMAL_FIELD, SUBSET_FIELD

Вы можете включить этот файл несколько раз, переосмысление этих структур для каждого прохода. Первый из них будет повернуть Определяет в нормальную структуру, с обоими типами поля выводится как обычно. Второй будет определять NORMAL_FIELD не имеет ничего, и было бы создать подмножество. Третий создаст соответствующий код для копирования полого подмножества более.

Вы будете в конечном итоге с одним определением структуры, что позволяет контролировать, какие поля в подмножестве и автоматически создает подходящий для вас код.

Ответил 19/05/2009 в 13:13
источник пользователем

голоса
11

Из вашего описания, это выглядит, как у вас есть доступ и может изменить вашу первоначальную структуру. Я предлагаю вам реорганизовать подструктуры в полный тип (как вы это делали в вашем примере), а затем сделать эту структуру поля на большой структуре, герметизирующего все эти поля в исходной структуры в меньшем составе.

Расширение на свой небольшой пример:

typedef struct 
{
  int a;
  char c;
} smallstruct;

typedef struct 
{
  int b;
  smallstruct mysub;
} bigstruct;

Доступ к информации smallstruct будет сделано так:

/* stack-based allocation */
bigstruct mybig;
mybig.mysub.a = 1;
mybig.mysub.c = '1';
mybig.b = 2;

/* heap-based allocation */
bigstruct * mybig = (bigstruct *)malloc(sizeof(bigstruct));
mybig->mysub.a = 1;
mybig->mysub.c = '1';
mybig->b = 2;

Но вы также можете обойти указатели на небольшую структуру:

void dosomething(smallstruct * small)
{ 
  small->a = 3;
  small->c = '3';
}

/* stack based */    
dosomething(&(mybig.mysub));

/* heap based */    
dosomething(&((*mybig).mysub));

Выгоды:

  • Нет Макросы
  • Нет внешних зависимостей
  • Нет памяти порядка литья писаки
  • Уборщик, проще для чтения и использования кода.
Ответил 19/05/2009 в 13:14
источник пользователем

голоса
0

Просто, чтобы помочь вам в получении метаданных, вы можете обратиться к offsetof () макрос, который также имеет преимущество заботиться о каких-либо дополнений вы можете иметь

Ответил 19/05/2009 в 13:17
источник пользователем

голоса
0

Я предлагаю принять этот подход:

  1. Проклятие парня, который написал большую структуру. Получите куклу вуду и повеселиться.
  2. Марк каждое поле большой структуры, что вам нужно каким-то образом (макро или комментарий или что-то)
  3. Написать небольшой инструмент, который считывает заголовочный файл и извлекает отмеченные поля. Если вы используете комментарии, вы можете дать каждому полю приоритета или что-то отсортировать их.
  4. Написать новый файл заголовок для подструктуры (используя фиксированный верхние и нижние колонтитулы).
  5. Написать новый файл C , который содержит функцию , createSubStructкоторая принимает указатель на большие структуры и возвращает указатель на substruct
  6. В функции, петля над полями собраны и излучают ss.field = bs.field(т.е. скопировать полей по одному).
  7. Добавьте маленький инструмент для вашего Makefile и добавить новый заголовок и исходный файл C для вашей сборки

Я предлагаю использовать gawk, или любой язык сценариев , вы комфортно, как инструмент; который должен занять полчаса , чтобы построить.

[EDIT] Если вы действительно хотите попробовать отражение (который я предлагаю против, это будет много работы действительно получают , что работает в C), то offsetof()макрос является вашим другом. Этот макрос возвращает смещение поля в структуре (который чаще всего не сумма размеров полей перед ним). См этой статьи .

[EDIT2] Не записывайте свой собственный парсер. Чтобы получить свое собственное право парсера будет принимать месяцев; Я знаю, так как я написал много парсеров в моей жизни. Вместо того, чтобы пометить части исходного файла заголовка, которые должны быть скопированы, а затем полагаться на один синтаксический анализатор, который вы знаете, работает: один из вашего компилятора Си. Вот несколько идей, как сделать эту работу:

struct big_struct {
    /**BEGIN_COPY*/
    int i;
    int j : 3;
    int k : 2;
    char * str;
    /**END_COPY*/
    ...
    struct x y; /**COPY_STRUCT*/
}

Просто иметь свой инструмент скопировать что - нибудь между /**BEGIN_COPY*/и /**END_COPY*/.

Используйте специальные комментарии , как /**COPY_STRUCT*/инструктировать ваш инструмент для генерации memcpy()вместо присваивания и т.д.

Это может быть написано и отлажено в течение нескольких часов. Это займет больше времени, чтобы создать парсер для C без каких-либо функциональных возможностей; то есть вы просто то, что может читать действительные C, но вы все равно должны написать часть анализатора, понятный C, и ту часть, которая делает что-то полезное с данными.

Ответил 19/05/2009 в 13:45
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more