Это называется составной литерал и задокументировано в разделе 6.5.2.5 C стандарта .
Ниже приводится выдержка из этого раздела:
3 Постфиксное выражение, состоящее из имени типа в скобках, за которым следует заключенный в скобки список инициализаторов, представляет собой составной литерал .Он предоставляет безымянный объект, значение которого задается списком инициализатора.
4 Если имя типа задает массив неизвестного размера, размер определяется списком инициализатора, как указано в 6.7..9, а тип составного литерала - тип завершенного массива.В противном случае (когда имя типа указывает тип объекта), тип составного литерала соответствует типу, указанному в имени типа.В любом случае результатом является lvalue.
5 Значение составного литерала - это значение безымянного объекта, инициализированного списком инициализатора.Если составной литерал находится вне тела функции, объект имеет статическую продолжительность хранения;в противном случае он имеет автоматическую продолжительность хранения, связанную с вмещающим блоком.
В вашем случае составной литерал предназначен для struct
, но они также могут быть созданы для массивов.В параграфе 8 приведен пример:
8 ПРИМЕР 1 Определение области файла
int *p = (int []){2, 4};
инициализирует p
, чтобы указывать на первый элемент массиваиз двух целых, первый имеет значение два, а второй - четыре.Выражения в этом составном литерале должны быть постоянными.У безымянного объекта есть статическая продолжительность хранения.
Обратите внимание также, что составной литерал является lvalue, что означает, что вы можете взять его адрес:
Pos *p = &( Pos ){ f->line, f->column + delta };
Этот объект имеет время жизни, связанноес его областью, означающей, что как только область заканчивается, объект больше не существует.Поэтому не носите его адрес после того, как он выходит из области видимости.
Вы также можете использовать составной литерал с обозначенным инициализатором :
return ( Pos ){ .line=f->line, .column=f->column + delta };