Struct and union initialization
При инициализации объекта типа struct или union инициализатор должен быть непустым, (до C23) заключенным в фигурные скобки, разделенным запятыми списком инициализаторов для членов:
=
{
выражение
,
...
}
|
(1) | (до C99) | |||||||
=
{
дескриптор
(опционально)
выражение
,
...
}
|
(2) | (начиная с C99) | |||||||
=
{
}
|
(3) | (начиная с C23) | |||||||
где
designator
представляет собой последовательность (разделенную пробелами или смежную) отдельных обозначений членов вида
.
member
и
array designators
вида
[
index
]
.
Все члены, которые не инициализированы явно, пусто-инициализированы .
Содержание |
Объяснение
При инициализации union список инициализаторов должен содержать только один элемент, который инициализирует первый член объединения если не используется designated initializer (since C99) .
union { int x; char c[4]; } u = {1}, // делает u.x активным со значением 1 u2 = { .c={'\1'} }; // делает u2.c активным со значением {'\1','\0','\0','\0'}
При инициализации struct первый инициализатор в списке инициализирует первый объявленный член (если не указан дезигнатор) (начиная с C99) , а все последующие инициализаторы без дезигнаторов (начиная с C99) инициализируют члены struct, объявленные после члена, инициализированного предыдущим выражением.
struct point {double x,y,z;} p = {1.2, 1.3}; // p.x=1.2, p.y=1.3, p.z=0.0 div_t answer = {.quot = 2, .rem = -1 }; // порядок элементов в div_t может варьироваться
|
Дезигнатор заставляет следующий инициализатор инициализировать член структуры, описанный дезигнатором. Затем инициализация продолжается вперед в порядке объявления, начиная со следующего элемента, объявленного после элемента, описанного дезигнатором. struct {int sec,min,hour,day,mon,year;} z = {.day=31,12,2014,.sec=30,15,17}; // initializes z to {30,15,17,31,12,2014} |
(since C99) |
Ошибка предоставить больше инициализаторов, чем членов.
Вложенная инициализация
Если члены структуры или объединения являются массивами, структурами или объединениями, соответствующие инициализаторы в списке инициализаторов в фигурных скобках — это любые инициализаторы, допустимые для этих членов, за исключением того, что их фигурные скобки могут быть опущены следующим образом:
Если вложенный инициализатор начинается с открывающей фигурной скобки, весь вложенный инициализатор до закрывающей фигурной скобки инициализирует соответствующий объект-член. Каждая левая открывающая фигурная скобка устанавливает новый текущий объект . Члены текущего объекта инициализируются в их естественном порядке , если не используются десигнаторы (начиная с C99) : элементы массива в порядке индексов, члены структуры в порядке объявления, только первый объявленный член любого объединения. Подобъекты внутри текущего объекта, которые не инициализированы явно к моменту закрывающей фигурной скобки, пусто-инициализируются .
struct example { struct addr_t { uint32_t port; } addr; union { uint8_t a8[4]; uint16_t a16[2]; } in_u; }; struct example ex = { // начало списка инициализации для struct example { // начало списка инициализации для ex.addr 80 // инициализирован единственный член структуры }, // конец списка инициализации для ex.addr { // начало списка инициализации для ex.in_u {127,0,0,1} // инициализирует первый элемент объединения } };
Если вложенный инициализатор не начинается с открывающей фигурной скобки, из списка берётся только достаточное количество инициализаторов для элементов или членов массива, структуры или объединения; оставшиеся инициализаторы используются для инициализации следующего члена структуры:
struct example ex = {80, 127, 0, 0, 1}; // 80 инициализирует ex.addr.port // 127 инициализирует ex.in_u.a8[0] // 0 инициализирует ex.in_u.a8[1] // 0 инициализирует ex.in_u.a8[2] // 1 инициализирует ex.in_u.a8[3]
|
Когда спецификаторы вложены, спецификаторы для членов следуют за спецификаторами для охватывающих структур/объединений/массивов. В любой вложенной списковой инициализации в фигурных скобках самый внешний спецификатор ссылается на текущий объект и выбирает подчинённый объект для инициализации только в пределах текущего объекта . struct example ex2 = { // current object is ex2, designators are for members of example .in_u.a8[0]=127, 0, 0, 1, .addr=80}; struct example ex3 = {80, .in_u={ // changes current object to the union ex.in_u 127, .a8[2]=1 // this designator refers to the member of in_u } }; Если любой подчинённый объект инициализируется явно дважды (что может произойти при использовании спецификаторов), используется инициализатор, который появляется позже в списке (более ранний инициализатор может не вычисляться): Хотя любые неинициализированные подчинённые объекты инициализируются неявно, неявная инициализация подчинённого объекта никогда не переопределяет явную инициализацию того же подчинённого объекта, если она появилась ранее в списке инициализации (выберите clang для наблюдения корректного вывода):
Запустить этот код
#include <stdio.h> typedef struct { int k; int l; int a[2]; } T; typedef struct { int i; T t; } S; T x = {.l = 43, .k = 42, .a[1] = 19, .a[0] = 18 }; // x initialized to {42, 43, {18, 19} } int main(void) { S l = { 1, // initializes l.i to 1 .t = x, // initializes l.t to {42, 43, {18, 19} } .t.l = 41, // changes l.t to {42, 41, {18, 19} } .t.a[1] = 17 // changes l.t to {42, 41, {18, 17} } }; printf("l.t.k is %d\n", l.t.k); // .t = x sets l.t.k to 42 explicitly // .t.l = 41 would zero out l.t.k implicitly } Вывод: l.t.k is 42 Однако, когда инициализатор начинается с открывающей фигурной скобки, его текущий объект полностью переинициализируется, и любые предыдущие явные инициализаторы для любых его подчинённых объектов игнорируются: struct fred { char s[4]; int n; }; struct fred x[ ] = { { { "abc" }, 1 }, // inits x[0] to { {'a','b','c','\0'}, 1 } [0].s[0] = 'q' // changes x[0] to { {'q','b','c','\0'}, 1 } }; struct fred y[ ] = { { { "abc" }, 1 }, // inits y[0] to { {'a','b','c','\0'}, 1 } [0] = { // current object is now the entire y[0] object .s[0] = 'q' } // replaces y[0] with { {'q','\0','\0','\0'}, 0 } }; |
(начиная с C99) |
Примечания
Список инициализации может иметь завершающую запятую, которая игнорируется.
struct {double x,y;} p = {1.0, 2.0, // завершающая запятая допустима };
|
В языке C список инициализаторов в фигурных скобках не может быть пустым (обратите внимание, что C++ допускает пустые списки, а также учтите, что struct в C не может быть пустым): |
(до C23) |
|
Список инициализаторов может быть пустым в C, как и в C++: |
(начиная с C23) |
struct {int n;} s = {0}; // OK struct {int n;} s = {}; // Ошибка до C23: список инициализации не может быть пустым // OK начиная с C23: s.n инициализируется в 0 struct {} s = {}; // Ошибка: структура не может быть пустой
|
Каждое выражение в списке инициализаторов должно быть константным выражением при инициализации агрегатов любой продолжительности хранения. |
(до C99) |
|
Как и при любой другой инициализации , каждое выражение в списке инициализаторов должно быть константным выражением при инициализации агрегатов со статической или поточно-локальной (начиная с C11) продолжительностью хранения : static struct {char* p} s = {malloc(1)}; // error Порядок вычисления подвыражений в любом инициализаторе неопределенно последователен (но не в C++, начиная с C++11): int n = 1; struct {int x,y;} p = {n++, n++}; // unspecified, but well-defined behavior: // n is incremented twice in arbitrary order // p equal {1,2} and {2,1} are both valid |
(начиная с C99) |
Пример
|
Этот раздел не завершён
Причина: больше практических примеров, возможно инициализация некоторых структур сокетов |
#include <stdio.h> #include <time.h> int main(void) { char buff[70]; // designated initializers simplify the use of structs whose // order of members is unspecified struct tm my_time = { .tm_year=2012-1900, .tm_mon=9, .tm_mday=9, .tm_hour=8, .tm_min=10, .tm_sec=20 }; strftime(buff, sizeof buff, "%A %c", &my_time); puts(buff); }
Возможный вывод:
Sunday Sun Oct 9 08:10:20 2012
Ссылки
- Стандарт C17 (ISO/IEC 9899:2018):
-
- 6.7.9/12-39 Инициализация (стр. 101-105)
- Стандарт C11 (ISO/IEC 9899:2011):
-
- 6.7.9/12-38 Инициализация (стр. 140-144)
- Стандарт C99 (ISO/IEC 9899:1999):
-
- 6.7.8/12-38 Инициализация (стр. 126-130)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
-
- 6.5.7 Инициализация
Смотрите также
|
C++ documentation
для
Aggregate initialization
|