В C, указатель на структуру всегда указывает на его первый член?

Предположим, что у меня есть несколько 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 начинаются с члена Base.

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

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

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

Ответ 1

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

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

Ответ 2

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

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 *? Я не вижу, что это гораздо больше работы, и у нее есть преимущество безопасности типов.