Spec-Zone.ru › GCC 15

6.2.10 Составные литералы

Составной литерал выглядит как приведение типа для списка инициализаторов агрегата, заключённого в фигурные скобки. Его значение — объект типа, указанного в приведении, содержащий элементы, заданные в инициализаторе. В отличие от результата приведения типа, составной литерал является lvalue. ISO C99 и более поздние стандарты поддерживают составные литералы. В качестве расширения GCC поддерживает составные литералы также в режиме C90 и в C++, хотя, как объясняется ниже, семантика в C++ несколько отличается.

Обычно указанный тип составного литерала — структура. Предположим, что struct foo и structure объявлены следующим образом:

struct foo {int a; char b[2];} structure;

Вот пример создания struct foo с помощью составного литерала:

structure = ((struct foo) {x + y, 'a', 0});

Это эквивалентно следующей записи:

{
  struct foo temp = {x + y, 'a', 0};
  structure = temp;
}

Можно также создать массив, однако в C++ это опасно, как объясняется ниже. Если все элементы составного литерала являются (или состоят из) простых константных выражений, подходящих для использования в инициализаторах объектов со статической длительностью хранения, составной литерал можно преобразовать в указатель на его первый элемент и использовать в таком инициализаторе, как показано здесь:

char **foo = (char *[]) { "x", "y", "z" };

Допускаются также составные литералы скалярных типов и типов объединений. В следующем примере переменная i инициализируется значением 2 — результатом увеличения безымянного объекта, созданного составным литералом.

int i = ++(int) { 1 };

В качестве расширения GNU GCC разрешает инициализировать объекты со статической длительностью хранения составными литералами (что невозможно в ISO C99, поскольку инициализатор не является константой). Если типы составного литерала и объекта совпадают, он обрабатывается так, как если бы объект инициализировался только списком, заключённым в фигурные скобки. Элементы составного литерала должны быть константами. Если инициализируемый объект имеет массив неизвестного размера, размер определяется размером составного литерала.

static struct foo x = (struct foo) {1, 'a', 'b'};
static int y[] = (int []) {1, 2, 3};
static int z[] = (int [3]) {1};

Приведённые выше строки эквивалентны следующему:

static struct foo x = {1, 'a', 'b'};
static int y[] = {1, 2, 3};
static int z[] = {1, 0, 0};

В C составной литерал обозначает безымянный объект со статической или автоматической длительностью хранения. В C++ составной литерал обозначает временный объект, который существует только до конца полного выражения. В результате корректный код C, получающий адрес подобъекта составного литерала, может быть некорректным в C++, поэтому G++ отклоняет преобразование временного массива в указатель. Например, если бы приведённый выше пример составного литерала массива находился внутри функции, любое последующее использование foo в C++ приводило бы к неопределённому поведению, поскольку время жизни массива заканчивается после объявления foo.

В целях оптимизации G++ иногда продлевает время жизни составных литералов-массивов: когда массив находится вне функции или имеет тип с квалификатором const. Если бы foo и его инициализатор содержали элементы типа char *const, а не char *, или если бы foo была глобальной переменной, массив имел бы статическую длительность хранения. Но, вероятно, безопаснее просто избегать использования составных литералов-массивов в коде C++.

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/Compound-Literals.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API