В C всегда ли указатель на структуру всегда указывает на ее первый член? - PullRequest
32 голосов
/ 06 сентября 2011

Предположим, у меня есть несколько структур C, для которых я хотел бы работать с определенным набором функций.

Мне интересно, является ли следующий подход допустимым:

typedef struct Base {
     int exampleMember;
     // ...
} Base;

typedef struct Foo {
     Base base;
     // ...
} Foo;

typedef struct Bar {
     Base base;
     // ...
} Bar;

void MethodOperatesOnBase(void *);

void MethodOperatesOnBase(void * obj)
{
     Base * base = obj;
     base->exampleMember++;
}

В этом примере вы заметите, что обе структуры Foo и Bar начинаются с Basemember.

И, что в MethodOperatesOnBase я приведу параметр void * к Base *.

Я бы хотел передать указатели на Bar и указатели на Foo к этому методу и полагаться на то, что первый член структуры будет Base struct.

Это приемлемо, или есть некоторые (возможно, специфичные для компилятора) проблемы, о которых мне нужно знать?(Например, какая-то схема упаковки / заполнения, которая изменила бы местоположение первого члена структуры?)

Ответы [ 3 ]

38 голосов
/ 06 сентября 2011

Да, стандарт C специально гарантирует, что это будет работать.

(C1x §6.7.2.1.13: «Указатель на объект структуры, надлежащим образом преобразованный, указывает на его начальный член ... и наоборот. Внутри объекта структуры может быть безымянное заполнение, но не в его начале» ".)

2 голосов
/ 05 ноября 2011

Так реализован весь gtk +.Я не могу придумать лучшего примера.Взгляните на http://git.gnome.org/browse/gtk+/tree/gtk/

1 голос
/ 06 сентября 2011

Я не согласен ни с одним из ответов о том, что то, что вы предложили, будет работать, но в интересах более полного обсуждения (не предлагая вам использовать C ++!), Почему бы не сделать что-то вроде

typedef struct Base ...  /* The types defined exactly as before */
typedef struct Foo ...
typedef struct Bar ...

/* The function takes a Base* since that is what it actually works with*/
void MethodOperatesOnBase(Base* pbase)
{
    /* Do something... */
}

/* Now call it like this: */
Foo foo;
Bar bar;

MethodOperatesOnBase(&foo.base);
MethodOperatesOnBase(&bar.base);

Есть ли какая-то причина, которая не будет работать, и вам нужно использовать void *? Я не вижу, что это намного больше работы, и она имеет преимущество безопасности типов.

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