Инициализировать структуру без присваивания?

Я не смог найти ответ на этот вопрос в Интернете, поэтому вот мой вопрос: могу ли я определить экземпляр структуры, не назначая его локальной или глобальной переменной в C? Например:

struct A {
  int b;
}

struct A foo() {
  return struct A { .b = 42 };
}

Если это невозможно: почему?

3 ответа

Решение

Да, C99 предоставляет составные литералы для этого ( посмотрите вживую):

return (struct A) {  42 } ;

который рассматривается в разделе стандарта проекта C99 6.5.2.5 Составные литералы и говорит:

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

а также:

Значение составного литерала - это значение безымянного объекта, инициализированного списком инициализатора. Если составной литерал находится вне тела функции, объект имеет статическую продолжительность хранения; в противном случае он имеет автоматическую продолжительность хранения, связанную с окружающим блоком.

и приводит несколько примеров, в том числе:

Пример 3. Инициализаторы с обозначениями могут быть объединены с составными литералами. Объекты структуры, созданные с использованием составных литералов, могут быть переданы в функции независимо от порядка членов:

drawline((struct point){.x=1, .y=1}, (struct point){.x=3, .y=4});

gcc также есть хороший документ по этому вопросу в разделе расширений, поскольку он поддерживает эту функцию за пределами C99, а также clang,

Да, вы можете использовать составные литералы в C99 и позже.

return (struct A) { .b = 42 };

Вы даже можете указать на них:

struct A *a = &(struct A) { .b = 42 };
a->b = 43;

Эти литералы "лучше" строковых литералов в том смысле, что они доступны для записи. Компилятор может объединить их, если и только если вы включите const в типе литерала.

Да, это возможно с C99. Это сложный буквальный.

Тем не менее, у вас неправильный синтаксис. Использование:

(struct A){.b=42}

или же

(struct A){42}

Тем не менее, перейдите на постоянные литералы, если это не имеет значения:

(const struct A){.b=42}

Все константные литералы подлежат постоянному пулу (включая строковые литералы, которые имеют тип char[] по историческим причинам).
Постоянные составные литералы и составные литералы вне любой функции имеют статическую длительность хранения,
остальные имеют автоматическую продолжительность хранения (остерегайтесь возврата указателя, также они должны каждый раз инициализироваться).

Таким образом, по возможности, предпочитайте постоянные литералы.

Другие вопросы по тегам