C - Создание анонимного экземпляра структуры

В этом коде структура определяется следующим образом:

typedef struct
{
    int line;
    int column;
} Pos;

И позже использовал этот способ:

Pos get_pos ( int delta )
{
    ...

    return ( Pos ){ f->line, f->column + delta };
}

Строка return ( Pos ){ f->line, f->column + delta } кажется, создает анонимный экземпляр структуры Pos с инициализированными значениями. Как называется эта техника и как она работает? Где я могу узнать больше об этом?

Ответы

Ответ 1

Это называется составным литералом и задокументировано в разделе 6.5.2.5 стандарта C.

Вот выдержка из этого раздела:

3 Постфиксное выражение, состоящее из имени типа в скобках, за которым следует список инициализаторов, заключенный в brace-, является составным литералом. Он предоставляет неназванный объект, значение которого задается списком инициализатора.

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 };