En C, ¿un puntero a una estructura apunta siempre a su primer miembro?

Supongamos que tengo un número de estructuras C sobre las cuales me gustaría que operara un conjunto particular de funciones.

Me pregunto si el siguiente es un enfoque legítimo:

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

En el ejemplo, notará que ambas estructuras, Foo y Bar comienzan con un miembro Base .

Y, en MethodOperatesOnBase , echo el parámetro void * a Base * .

Me gustaría pasarle los punteros a Bar y los indicadores a Foo con este método y confiar en que el primer miembro de la estructura sea una estructura Base .

¿Es esto aceptable, o hay algunos problemas (posiblemente específicos del comstackdor) que debo tener en cuenta? (¿Como algún tipo de esquema de relleno / relleno que cambiaría la ubicación del primer miembro de una estructura?)

Sí, el estándar C específicamente garantiza que esto funcionará.

(C1x §6.7.2.1.13: “Un puntero a un objeto de estructura, convenientemente convertido, apunta a su miembro inicial … y viceversa. Puede haber un relleno sin nombre dentro de un objeto de estructura, pero no al principio”).

No estoy en desacuerdo con ninguna de las respuestas que dice que lo que sugirió funcionará, pero en aras de una discusión más completa (¡sin sugerir que use C ++!), ¿Por qué no hacer algo como esto?

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

¿Hay algún motivo por el que no funcione y deba usar void * ? No veo que esto sea mucho más trabajo y tiene la ventaja de la seguridad de tipo.

Todo el gtk + se implementa así. No puedo pensar en un mejor ejemplo. Eche un vistazo a http://git.gnome.org/browse/gtk+/tree/gtk/