Struct declaration
Una estructura es un tipo que consiste en una secuencia de miembros cuyo almacenamiento se asigna en una secuencia ordenada (a diferencia de una unión, que es un tipo que consiste en una secuencia de miembros cuyo almacenamiento se superpone).
El
especificador de tipo
para una estructura es idéntico al
union
especificador de tipo excepto por la palabra clave utilizada:
Contenidos |
Sintaxis
struct
attr-spec-seq
(opcional)
name
(opcional)
{
struct-declaration-list
}
|
(1) | ||||||||
struct
attr-spec-seq
(opcional)
name
|
(2) | ||||||||
struct
name
;
,
declara
pero no define la estructura
name
(ver declaración anticipada abajo). En otros contextos, nombra la estructura previamente declarada, y
attr-spec-seq
no está permitido.
| name | - | el nombre de la estructura que se está definiendo |
| struct-declaration-list | - | cualquier número de declaraciones de variables, campos de bits , y aserciones estáticas . No se permiten miembros de tipo incompleto ni miembros de tipo función (excepto para el miembro de arreglo flexible descrito a continuación) |
| attr-spec-seq | - | (C23) lista opcional de atributos , aplicados al tipo de estructura |
Explicación
Dentro de un objeto struct, las direcciones de sus elementos (y las direcciones de las unidades de asignación de campos de bits) aumentan en el orden en que los miembros fueron definidos. Un puntero a un struct puede convertirse a un puntero a su primer miembro (o, si el miembro es un campo de bits, a su unidad de asignación). Del mismo modo, un puntero al primer miembro de un struct puede convertirse a un puntero al struct que lo contiene. Puede haber relleno sin nombre entre dos miembros cualesquiera de un struct o después del último miembro, pero no antes del primer miembro. El tamaño de un struct es al menos tan grande como la suma de los tamaños de sus miembros.
|
Si una estructura define al menos un miembro con nombre, se le permite declarar adicionalmente su último miembro con tipo de arreglo incompleto. Cuando se accede a un elemento del miembro de arreglo flexible (en una expresión que utiliza el operador
struct s { int n; double d[]; }; // s.d is a flexible array member struct s t1 = { 0 }; // OK, d is as if double d[1], but UB to access struct s t2 = { 1, { 4.2 } }; // error: initialization ignores flexible array // if sizeof (double) == 8 struct s *s1 = malloc(sizeof (struct s) + 64); // as if d was double d[8] struct s *s2 = malloc(sizeof (struct s) + 40); // as if d was double d[5] s1 = malloc(sizeof (struct s) + 10); // now as if d was double d[1]. Two bytes excess. double *dp = &(s1->d[0]); // OK *dp = 42; // OK s1->d[1]++; // Undefined behavior. 2 excess bytes can't be accessed // as double. s2 = malloc(sizeof (struct s) + 6); // same, but UB to access because 2 bytes are // missing to complete 1 double dp = &(s2->d[0]); // OK, can take address just fine *dp = 42; // undefined behavior *s1 = *s2; // only copies s.n, not any element of s.d // except those caught in sizeof (struct s) |
(desde C99) |
|
Similar a union, un miembro sin nombre de una struct cuyo tipo es una struct sin nombre se conoce como estructura anónima . Cada miembro de una estructura anónima se considera miembro de la estructura o unión contenedora, manteniendo su diseño de estructura. Esto se aplica recursivamente si la estructura o unión contenedora también es anónima. struct v { union // anonymous union { struct { int i, j; }; // anonymous structure struct { long k, l; } w; }; int m; } v1; v1.i = 2; // valid v1.k = 3; // invalid: inner structure is not anonymous v1.w.k = 5; // valid Similar a union, el comportamiento del programa es indefinido si struct se define sin ningún miembro nombrado (incluyendo aquellos obtenidos mediante estructuras o uniones anidadas anónimas). |
(desde C11) |
Declaración anticipada
Una declaración de la siguiente forma
struct
attr-spec-seq
(opcional)
name
;
|
|||||||||
oculta cualquier significado previamente declarado para el nombre name en el espacio de nombres de etiquetas y declara name como un nuevo nombre de struct en el ámbito actual, que será definido posteriormente. Hasta que aparezca la definición, este nombre de struct tiene tipo incompleto .
Esto permite que las estructuras se refieran entre sí:
struct y; struct x { struct y *p; /* ... */ }; struct y { struct x *q; /* ... */ };
Tenga en cuenta que un nuevo nombre de struct también puede introducirse simplemente usando una struct tag dentro de otra declaración, pero si ya existe un struct previamente declarado con el mismo nombre en el name space de etiquetas, la etiqueta se referiría a ese nombre
struct s* p = NULL; // la etiqueta que nombra una estructura desconocida la declara struct s { int a; }; // definición de la estructura apuntada por p void g(void) { struct s; // declaración anticipada de una nueva estructura s local // esto oculta la estructura s global hasta el final de este bloque struct s *p; // puntero a la estructura s local // sin la declaración anticipada anterior, // esto apuntaría a la s de ámbito de archivo struct s { char* p; }; // definición de la estructura s local }
Palabras clave
Notas
Consulte inicialización de estructuras para conocer las reglas sobre los inicializadores de estructuras.
Debido a que no se permiten miembros de tipo incompleto, y un tipo de estructura no está completo hasta el final de la definición, una estructura no puede tener un miembro de su propio tipo. Se permite un puntero a su propio tipo, y se utiliza comúnmente para implementar nodos en listas enlazadas o árboles.
Debido a que una declaración de struct no establece un scope , los tipos anidados, enumeraciones y enumeradores introducidos por declaraciones dentro de la struct-declaration-list son visibles en el scope circundante donde se define el struct.
Ejemplo
#include <stddef.h> #include <stdio.h> int main(void) { // Declarar el tipo de estructura. struct car { char* make; int year; }; // Declarar e inicializar un objeto de un tipo de estructura previamente declarado. struct car c = {.year = 1923, .make = "Nash"}; printf("1) Car: %d %s\n", c.year, c.make); // Declarar un tipo de estructura, un objeto de ese tipo y un puntero al mismo. struct spaceship { char* model; int max_speed; } ship = {"T-65 X-wing starfighter", 1050}, *pship = &ship; printf("2) Spaceship: %s. Max speed: %d km/h\n\n", ship.model, ship.max_speed); // La dirección aumenta en orden de definición. Se puede insertar relleno. struct A { char a; double b; char c; }; printf( "3) Offset of char a = %zu\n" "4) Offset of double b = %zu\n" "5) Offset of char c = %zu\n" "6) Size of struct A = %zu\n\n", offsetof(struct A, a), offsetof(struct A, b), offsetof(struct A, c), sizeof(struct A) ); struct B { char a; char b; double c; }; printf( "7) Offset of char a = %zu\n" "8) Offset of char b = %zu\n" "9) Offset of double c = %zu\n" "A) Size of struct B = %zu\n\n", offsetof(struct B, a), offsetof(struct B, b), offsetof(struct B, c), sizeof(struct B) ); // Un puntero a una estructura puede convertirse a un puntero // a su primer miembro y viceversa. char** pmodel = (char **)pship; printf("B) %s\n", *pmodel); pship = (struct spaceship *)pmodel; }
Salida posible:
1) Car: 1923 Nash 2) Spaceship: T-65 X-wing starfighter. Max speed: 1050 km/h 3) Offset of char a = 0 4) Offset of double b = 8 5) Offset of char c = 16 6) Size of struct A = 24 7) Offset of char a = 0 8) Offset of char b = 1 9) Offset of double c = 8 A) Size of struct B = 16 B) T-65 X-wing starfighter
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| DR 499 | C11 | los miembros de structs/uniones anónimos se consideraban miembros del struct/unión contenedor | conservan su diseño de memoria |
Referencias
- Estándar C23 (ISO/IEC 9899:2024):
-
- 6.7.2.1 Especificadores de estructura y unión (p: TBD)
- Estándar C17 (ISO/IEC 9899:2018):
-
- 6.7.2.1 Especificadores de estructura y unión (p: 81-84)
- Estándar C11 (ISO/IEC 9899:2011):
-
- 6.7.2.1 Especificadores de estructura y unión (p: 112-117)
- Estándar C99 (ISO/IEC 9899:1999):
-
- 6.7.2.1 Especificadores de estructura y unión (p: 101-104)
- Estándar C89/C90 (ISO/IEC 9899:1990):
-
- 3.5.2.1 Especificadores de estructura y unión
Véase también
|
Documentación de C++
para
Declaración de clase
|