example - typedef struct uso
¿Qué es ''forward declaration'' y la diferencia entre ''typedef struct X'' y ''struct X''? (5)
Soy un principiante en la programación de C y sé la diferencia entre la declaración de tipo de estructura y la declaración de estructura typedef. Encontré una respuesta diciendo que si definimos una estructura como:
typedef struct
{
some members;
}struct_name;
Entonces será como proporcionar un alias a una estructura anónima (ya que no tiene un nombre de etiqueta). Por lo tanto, no se puede usar para la declaración directa. No sé lo que significa la "declaración directa".
Además, quería saberlo para el siguiente código:
typedef struct NAME
{
some members;
}struct_alias;
¿Hay alguna diferencia entre NAME
y struct_alias
? ¿O ambos son iguales ya que struct_alias es un alias de struct NAME?
Además, ¿podemos declarar una variable de tipo struct NAME
como estas?
struct_alias variable1;
y / o como:
struct NAME variable2;
o como:
NAME variable3;
Como otros dijeron antes, una declaración directa en C / C ++ es la declaración de algo con la definición real no disponible. Es una declaración que le dice al compilador "hay un tipo de datos ABC".
Vamos a pretender que este es un encabezado para algunos key / value store my_dict.h
:
...
struct my_dict_t;
struct my_dict_t* create();
char* get_value(const struct my_dict_t* dict, const char* name);
char* insert(struct my_dict_t* dict, const char* name, char* value);
void destroy(struct my_dict_t* dict);
...
No sabes nada sobre my_dict_t
, pero en realidad, para usar la tienda no necesitas saber:
#include "my_dict.h"
...
struct my_dict_t* dict = create();
if(0 != insert(dict, "AnEntry", strdup("AValue"))) {
...
}
...
La razón de esto es: solo está utilizando POINTERS para la estructura de datos.
Los punteros son solo números, y para lidiar con ellos no es necesario saber a qué apuntan.
Esto solo importará si intenta acceder a ellos de verdad, como
struct my_dict_t* dict = create();
printf("%s/n", dict->value); /* Impossible if only a forward decl is available */
Entonces, para implementar las funciones, necesita una definición real de my_struct_t
. Puede hacer esto en el archivo de origen my_dict.c
manera:
#include "my_dict.h"
struct my_dict_t {
char* value;
const char* name;
struct my_dict_t* next;
}
struct my_dict_t* create() {
return calloc(1, sizeof(struct my_dict_t));
}
Esto es útil para varias situaciones, como
- Para resolver dependencias de tipo circular, como explicó Sergei L.
- Para la encapsulación, como en el ejemplo anterior.
Entonces, la pregunta que queda es: ¿Por qué no podemos omitir la declaración directa cuando utilizamos las funciones anteriores? Al final, sería suficiente para el compilador saber que todos los dict
son punteros.
Sin embargo, el compilador realiza comprobaciones de tipo: necesita verificar que no hagas algo como
...
int i = 12;
char* value = get_value(&i, "MyName");
...
No necesita saber cómo se ve my_dict_t
, pero necesita saber que &i
no es el tipo de puntero que get_value()
espera.
las declaraciones de struct
hacia adelante pueden ser útiles cuando necesita tener declaraciones de estructura de bucle. Ejemplo:
struct a {
struct b * b_pointer;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
Cuando struct a
se declara, aún no conoce las especificaciones de struct b
, pero puede reenviarla.
Cuando tipea una estructura anónima, el compilador no le permitirá usar su nombre antes de typedef.
Esto es ilegal:
struct a {
b * b_pointer;
int c;
};
typedef struct {
struct a * a_pointer;
void * d;
} b;
// struct b was never declared or defined
Esto aunque es legal:
struct a {
struct b * b_pointer;
int c;
};
typedef struct b {
struct a * a_pointer;
void * d;
} b;
// struct b is defined and has an alias type called b
Asi es esto:
typedef struct b b;
// the type b referes to a yet undefined type struct b
struct a {
b * struct_b_pointer;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
Y esto:
typedef int b;
struct a {
struct b * struct_b_pointer;
b b_integer_type;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
// struct b and b are two different types all together. Note: this is not allowed in C++
struct_alias
y struct NAME
son iguales, struct_alias
es un alias para struct NAME
Ambos son iguales y permitidos
struct_alias variable1;
struct NAME variable1;
esto es ilegal
NAME variable3;
Ver este artículo en la declaración de Forward
La declaración directa es una declaración que precede a una definición real, generalmente con el propósito de poder hacer referencia al tipo declarado cuando la definición no está disponible. Por supuesto, no todo se puede hacer con la estructura declarada no definida, pero en cierto contexto es posible usarla. Tal tipo se llama incompleto , y hay una serie de restricciones en su uso. Por ejemplo:
struct X; // forward declaration
void f(struct X*) { } // usage of the declared, undefined structure
// void f(struct X) { } // ILLEGAL
// struct X x; // ILLEGAL
// int n =sizeof(struct X); // ILLEGAL
// later, or somewhere else altogether
struct X { /* ... */ };
Esto puede ser útil, por ejemplo, para romper dependencias circulares, o reducir el tiempo de compilación, ya que las definiciones suelen ser significativamente más grandes, por lo que se necesitan más recursos para analizarlo.
En su ejemplo, struct NAME
y struct_alias
son de hecho equivalentes.
struct_alias variable1;
struct NAME variable2;
son correctos;
NAME variable3;
no es así, ya que en C se requiere la palabra clave struct
.
La declaración directa es una promesa de definir algo que usted hace a un compilador en el punto donde no se puede hacer la definición. El compilador puede usar su palabra para interpretar otras declaraciones que de otro modo no podría interpretar.
Un ejemplo común es una struct
diseñada para ser un nodo en una lista vinculada: debe poner un puntero a un nodo en la struct
, pero el compilador no le permitirá hacerlo sin una declaración directa o una etiqueta:
// Forward declaration
struct element;
typedef struct {
int value;
// Use of the forward declaration
struct element *next;
} element; // Complete definition
y entonces no se puede usar para la declaración directa
Creo que el punto del autor era que darle una etiqueta a tu struct
sería equivalente a una declaración a futuro:
typedef struct element {
int value;
// No need for a forward declaration here
struct element *next;
} element;