Различные типы структур между версиями системы.Это тупик - PullRequest
1 голос
/ 01 февраля 2012

Я работаю над настройкой iPhone, где мне нужно читать и изменять содержимое структуры. Тем не менее, определение структуры отличается в iOS 4.1, iOS 4.2 и iOS 5, и я хотел бы сохранить совместимость со всеми этими. Проблема не в том, что я не могу это сделать; проблема в том, что для меня не имеет смысла переписывать 100+ полностью идентичных строк кода для каждого обновления iOS, которое может изменить структуру.

Вместо того, чтобы слишком увлекаться фактической публикацией исходного кода из проекта без какого-либо контекста, я написал упрощенный пример задачи. Это слишком долго, чтобы включать в этот пост, поэтому я поместил его в Pastie здесь: http://pastie.org/3295629 Все детали проблемы включены в комментарии в этом Pastie.

Заранее благодарим за любую помощь, которую вы можете иметь. Я в полном замешательстве.

(Если вы хотите увидеть реальные структуры, с которыми я имею дело в проекте iOS: http://pastie.org/3296564)

Ответы [ 3 ]

1 голос
/ 01 февраля 2012

Звучит так, будто вы должны скрывать доступ к структуре за интерфейсом. Кусок кода из 100+ строк, о котором вы говорите, должен использовать не реальную структуру напрямую, а интерфейс.

например, если две разные версии похожи:

struct foo_v1 {
    int a;
    int b;
    long long c;
};

struct foo_v2 {
    int a;
    char x;
    int d;
};

Вы оберните интерфейс вокруг этого, который имеет:

struct abstract_foo {
    int version;
    int a;
    int b;
    long long c;        
    char x;
    int d;
};

struct astract_foo get_foo(void);
void set_foo(struct abstract_foo f);

Копии get_foo() и set_foo() между исходной структурой в структуру вашего интерфейса и обратно соответственно. Поле версии имеет значение 1 или 2, поэтому код, использующий эту структуру, может решить, какие поля использовать.

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

struct abstract_foo {
    int version;
    int *a;
    int *b;
    long long *c;        
    char *x;
    int *d;
};

Это всего лишь примеры, есть миллион способов создания абстракций в C.

0 голосов
/ 01 февраля 2012

Я не знаком с разработкой для iOS, но кажется, что наиболее естественным способом было бы скомпилировать три разных исполняемых файла, по одному для каждой версии iOS.Структура должна быть определена в некотором заголовочном файле, предоставленном iOS, но если это не так, вы можете использовать #ifdefs, чтобы выяснить, для какой версии iOS вы компилируете, и определить ее самостоятельно.

#if IOS == 4_1
typedef struct osdata {
int dengus, payness, fibbus;
} mydata;
#elsif IOS == 4_2
typedef struct osdata {
int dengus, payness, chonus, fibbus;
} mydata;
#endif

Если этопо какой-то причине это невозможно (например, Apple требует один исполняемый файл для всех операционных систем), тогда вам нужно сделать что-то более сложное.Я думаю, что создал бы собственную структуру с именем mydata, с которой я мог бы работать в большей части моего исходного кода.Когда мне нужно взаимодействовать с ОС, у меня будет несколько различных функций, которые преобразуют его в правильный поток байтов, который будет распознан этой конкретной версией ОС, или преобразуют его из структуры ОС в мою структуру.Делая это, вы абстрагируете различия в ОС и делаете так, что вы можете просто работать с одной структурой данных в большей части вашего кода.

0 голосов
/ 01 февраля 2012

Самый простой способ - использовать указатель на функцию.Функции (по одной для каждой версии) получают указатель void * (и, возможно, больше), приводят этот указатель к соответствующей структуре и выполняют свою работу.Интеллектуальное объединение также возможно.

Избегая указателей на функции, вы также можете сделать что-то вроде

switch (ver=get_version()) {
case 1: return do_version_1_stuff(ptr, 1,2,3);
case 2: return do_version_2_stuff(ptr, 1,2,3);
case 3: return do_version_3_stuff(ptr, 1,2,3);
default: fprintf(stderr, "Unknown version %d, call QC!\n", ver);
       return -1;
}

ОБНОВЛЕНИЕ: («интеллектуальное объединение» не выглядит четко определенным)

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

struct aaaa {
    int type;
    float value;
    };

struct bbbb {
    int type;
    float value;
    char *description;
    };

union a_or_b {
   struct aaaa a;
   struct bbbb b;
   };

Если члены не имеют общего поля первого типа,Поле типа может быть помещено вне объединения в структуру-оболочку:

struct kkkk {
    float value;
    };
struct llll {
    float value;
    char *description;
    };

struct k_or_l {
   int type;
   union {
       struct kkkk k;
       struct llll l;
       } u;
   };

union a_or_b *abp;
struct k_or_l *klp;

Ссылка на материал в объединении теперь будет проходить через abp->a.value или klp->u.k.value, например,

int value = abp->a.type==1 ?  abp->a.value : abp->b.value;

или, что еще лучше, используя switch (abp->type) {}.

...