Объявление структуры
Структура — это тип, состоящий из последовательности членов, хранилище для которых выделяется в упорядоченной последовательности (в отличие от объединения, которое является типом, состоящим из последовательности членов с перекрывающимся хранилищем).
Спецификатор типа для структуры идентичен спецификатору типа union, за исключением используемого ключевого слова:
Синтаксис
struct attr-spec-seq (необязательно) name (необязательно) { struct-declaration-list } | (1) | |
struct attr-spec-seq (необязательно) name | (2) |
struct name ;, объявляет, но не определяет структуру name (см. объявление с предварительным описанием ниже). В других контекстах обозначает ранее объявленную структуру, а attr-spec-seq не допускается.| name | - | имя определяемой структуры |
| struct-declaration-list | - | любое количество объявлений переменных, объявлений битовых полей и объявлений статических утверждений. Члены неполного типа и члены функционального типа не допускаются (за исключением описанного ниже члена гибкого массива) |
| attr-spec-seq | - | (C23)необязательный список атрибутов, применяемых к типу структуры |
Пояснение
Внутри объекта структуры адреса её элементов (и адреса единиц выделения битовых полей) возрастают в том порядке, в котором были определены члены. Указатель на структуру можно преобразовать в указатель на её первый член (или, если этот член является битовым полем, на его единицу выделения). Аналогично, указатель на первый член структуры можно преобразовать в указатель на охватывающую его структуру. Между любыми двумя членами структуры или после последнего члена могут находиться безымянные байты-заполнители, но перед первым членом их быть не может. Размер структуры не меньше суммы размеров её членов.
| Если структура определяет хотя бы один именованный член, её последний член может дополнительно иметь неполный тип массива. При обращении к элементу члена гибкого массива (в выражении, использующем оператор 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)
| (начиная с C99) |
| Аналогично объединению, безымянный член структуры, тип которого является структурой без name, называется анонимной структурой. Каждый член анонимной структуры считается членом охватывающей её структуры или объединения, при этом сохраняется расположение членов в памяти. Это правило применяется рекурсивно, если охватывающая структура или объединение также являются анонимными. 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
Аналогично объединению, поведение программы не определено, если структура определена без именованных членов (включая члены, полученные через анонимные вложенные структуры или объединения). | (начиная с C11) |
Объявление с предварительным описанием
Объявление следующей формы
struct attr-spec-seq (необязательно) name ; |
скрывает любое ранее объявленное значение имени name в пространстве имён тегов и объявляет name новым именем структуры в текущей области видимости, определение которой появится позднее. До появления определения это имя структуры имеет неполный тип.
Это позволяет структурам ссылаться друг на друга:
struct y;
struct x { struct y *p; /* ... */ };
struct y { struct x *q; /* ... */ };
Обратите внимание, что новое имя структуры также можно ввести, просто используя тег структуры в другом объявлении. Однако, если в пространстве имён тегов уже существует ранее объявленная структура с тем же именем, тег будет ссылаться на неё
struct s* p = NULL; // tag naming an unknown struct declares it
struct s { int a; }; // definition for the struct pointed to by p
void g(void)
{
struct s; // forward declaration of a new, local struct s
// this hides global struct s until the end of this block
struct s *p; // pointer to local struct s
// without the forward declaration above,
// this would point at the file-scope s
struct s { char* p; }; // definitions of the local struct s
}
Ключевые слова
Примечания
Правила, касающиеся инициализаторов структур, см. в разделе инициализация структур.
Поскольку члены неполного типа не допускаются, а тип структуры не является полным до конца определения, структура не может иметь член собственного типа. Указатель на собственный тип разрешён и часто используется для реализации узлов связанных списков или деревьев.
Поскольку объявление структуры не создаёт область видимости, вложенные типы, перечисления и элементы перечислений, введённые объявлениями в struct-declaration-list, видны в окружающей области видимости, где определяется структура.
Пример
#include <stddef.h>
#include <stdio.h>
int main(void)
{
// Declare the struct type.
struct car
{
char* make;
int year;
};
// Declare and initialize an object of a previously-declared struct type.
struct car c = {.year = 1923, .make = "Nash"};
printf("1) Car: %d %s\n", c.year, c.make);
// Declare a struct type, an object of that type, and a pointer to it.
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);
// Address increase in order of definition. Padding may be inserted.
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)
);
// A pointer to a struct can be cast to a pointer
// to its first member and vice versa.
char** pmodel = (char **)pship;
printf("B) %s\n", *pmodel);
pship = (struct spaceship *)pmodel;
}
Возможный вывод:
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
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C.
| DR | Применён к | Поведение согласно опубликованному тексту | Корректное поведение |
|---|---|---|---|
| DR 499 | C11 | члены анонимных структур/объединений считались членами охватывающей структуры/объединения | они сохраняют своё расположение в памяти |
Ссылки
- Стандарт C23 (ISO/IEC 9899:2024):
- 6.7.2.1 Спецификаторы структуры и объединения (стр.: TBD)
- Стандарт C17 (ISO/IEC 9899:2018):
- 6.7.2.1 Спецификаторы структуры и объединения (стр.: 81-84)
- Стандарт C11 (ISO/IEC 9899:2011):
- 6.7.2.1 Спецификаторы структуры и объединения (стр.: 112-117)
- Стандарт C99 (ISO/IEC 9899:1999):
- 6.7.2.1 Спецификаторы структуры и объединения (стр.: 101-104)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
- 3.5.2.1 Спецификаторы структуры и объединения
См. также
| Документация C++ для Объявление класса |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/c/language/struct