c circular-dependency

¿Resolver la dependencia de typedef circular?



circular-dependency (6)

¿Cuál es la mejor manera de resolver la siguiente dependencia circular en la definición de estas estructuras?
Tenga en cuenta la etiqueta del lenguaje C: estoy buscando una solución en el estándar gcc C.

typedef struct { char* name; int age; int lefthanded; People* friends; } Person; typedef struct { int count; int max; Person* data; } People;


Adelante-declara una de las estructuras:

struct people; typedef struct { /* same as before */ struct people* friends; } Person; typedef struct people { /* same as before */ } People;


En cuanto a la legibilidad:

typedef struct Foo_ Foo; typedef struct Bar_ Bar; struct Foo_ { Bar *bar; }; struct Bar_ { Foo *foo; };

Podría ser una buena idea evitar las typedef struct completo;


La respuesta está en la diferencia entre declaración y definición. Está intentando declarar y definir en el mismo paso (en el caso de un nuevo tipo a través de typedef). Debe dividir estos pasos en diferentes pasos para que el compilador sepa de lo que está hablando de antemano.

typedef struct Person Person; typedef struct People People; struct Person { char* name; int age; int lefthanded; People* friends; }; struct People { int count; int max; Person* data; };

Observe la adición de las dos definiciones de tipo ''vacías'' en la parte superior (declaraciones). Esto le dice al compilador que el nuevo tipo Person es del tipo ''struct Person'' para que cuando vea que dentro de la definición de struct People, sepa lo que significa.

En su caso particular, en realidad podría salirse con la suya solo con la declaración previa de typdef de Personas porque ese es el único tipo usado antes de que se defina. En el momento en que entras en la definición de estructura de Personas, ya has definido completamente el tipo Persona. Así que lo siguiente también funcionaría pero NO SE RECOMIENDA porque es frágil:

typedef struct People People; typedef struct { char* name; int age; int lefthanded; People* friends; } Person; struct People { int count; int max; Person* data; };

Si cambia el orden de las definiciones de la estructura (moviendo a la gente de la estructura por encima de typedef de Person), volverá a fallar. Eso es lo que hace que esto sea frágil y, por lo tanto, no recomendado.

Tenga en cuenta que este truco NO funciona si incluye una estructura del tipo especificado en lugar de un puntero a ella. Entonces, por ejemplo, lo siguiente NO se compilará :

typedef struct Bar Bar; struct Foo { Bar bar; }; struct Bar { int i; };

El código anterior da un error de compilador porque la barra de tipo está incompleta cuando intenta usarla dentro de la definición de estructura Foo. En otras palabras, no sabe cuánto espacio asignar para estructurar la barra de miembros porque no ha visto la definición de barra de estructura en ese punto.

Este código compilará :

typedef struct Foo Foo; typedef struct Bar Bar; typedef struct FooBar FooBar; struct Foo { Bar *bar; }; struct Bar { Foo *foo; }; struct FooBar { Foo foo; Bar bar; FooBar *foobar; };

Esto funciona, incluso con los punteros circulares dentro de Foo y Bar, porque los tipos ''Foo'' y ''Bar'' han sido declarados previamente (pero aún no están definidos) para que el compilador pueda construir un puntero para ellos.

Cuando llegamos a la definición de FooBar, hemos definido cuán grandes son tanto Foo como Bar para poder incluir los objetos reales allí. También podemos incluir un puntero autorreferencial para escribir FooBar porque hemos declarado previamente el tipo.

Tenga en cuenta que si mueve la definición de struct FooBar sobre las definiciones de struct Foo o Bar, no se compilará por el mismo motivo que en el ejemplo anterior (tipo incompleto).


Ya que Person solo quiere un puntero a People , debería estar bien simplemente predecir lo último:

typedef struct People People;

Luego cambie la segunda declaración para simplemente declarar usando la etiqueta struct, así:

struct People { int count; int max; Person data[]; };


struct People_struct; typedef struct { char* name; int age; int lefthanded; struct People_struct* friends; } Person; typedef struct People_struct { int count; int max; Person data[]; } People;


struct _People; typedef struct { char* name; int age; int lefthanded; struct _People* friends; } Person; struct _People { int count; int max; Person data[1]; };

Nota: Es Person data[]; ¿estándar?