Инициализировать структуру без присваивания?
Я не смог найти ответ на этот вопрос в Интернете, поэтому вот мой вопрос: могу ли я определить экземпляр структуры, не назначая его локальной или глобальной переменной в 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[]
по историческим причинам).
Постоянные составные литералы и составные литералы вне любой функции имеют статическую длительность хранения,
остальные имеют автоматическую продолжительность хранения (остерегайтесь возврата указателя, также они должны каждый раз инициализироваться).
Таким образом, по возможности, предпочитайте постоянные литералы.