C struct инициализация с использованием меток. Это работает, но как?
Вчера я нашел некоторый код инициализации структуры, который бросил меня в цикл. Вот пример:
typedef struct { int first; int second; } TEST_STRUCT;
void testFunc() {
TEST_STRUCT test = {
second: 2,
first: 1
};
printf("test.first=%d test.second=%d\n", test.first, test.second);
}
Удивительно (для меня), вот вывод:
-> testFunc
test.first=1 test.second=2
Как видите, структура инициализируется правильно. Я не знал, что помеченные заявления могут быть использованы таким образом. Я видел несколько других способов инициализации структуры, но я не нашел ни одного примера такого рода инициализации структуры ни в одном из часто задаваемых вопросов по Си. Кто-нибудь знает, как / почему это работает?
5 ответов
Вот раздел руководства по gcc, который объясняет синтаксис назначенных инициализаторов для структур и массивов:
В инициализаторе структуры укажите имя поля для инициализации с помощью ".fieldname =" перед значением элемента. Например, учитывая следующую структуру,
struct point { int x, y; };
следующая инициализация
struct point p = { .y = yvalue, .x = xvalue };
эквивалентно
struct point p = { xvalue, yvalue };
Другой синтаксис, который имеет то же значение, устарел после GCC 2.5, это 'fieldname:', как показано здесь:
struct point p = { y: yvalue, x: xvalue };
Соответствующую страницу можно найти здесь.
Ваш компилятор должен иметь аналогичную документацию.
Это не метки и не битовые поля.
Это синтаксис для инициализации членов структуры, начиная с дней до C99. Он не стандартизирован, но доступен, например, в gcc.
typedef struct { int y; int x; } POINT;
POINT p = { x: 1, y: 17 };
В C99 синтаксис для инициализации определенных членов структуры был впервые введен в стандарт, но выглядит немного иначе:
typedef struct { int y; int x; } POINT;
POINT p = { .x = 1, .y = 17 };
Да, как указывалось выше, это обозначенные инициализаторы, которые являются стандартными C, хотя вы должны перейти на использование точек вместо двоеточий. И, как вы заметили, большинство книг там по-прежнему застряли где-то в 1984 году в их синтаксисе и не упоминают их. Более интересные факты:
- При использовании назначенных инициализаторов все, что не указано, инициализируется в ноль. Это помогает с исключительно большими структурами, например:
typedef struct {
double a, b, c, d, e;
char label[100];
} too_many_type;
too_many_type tm = {.a = 1, .e = 2, .b=1.5};
assert(tm.a + tm.b + tm.c + tm.d + tm.e == 4.5);
assert(!strlen(label));
- Также вы можете использовать составную литеральную форму, чтобы использовать эту форму в строке без инициализации, например:
too_many_type tm2;
tm2 = (too_many_type) {.a = 3, .e=6};
Это действительно замечательные возможности, и они поддерживаются каждым компилятором C, о котором я могу думать, так как он является стандартом. Обидно, что они не так известны.
На самом деле это не "помеченные операторы", а способ присвоения начальных значений именованным полям в структуре.
Gcc выдает предупреждение о "устаревшем использовании назначенного инициализатора с": ", и в C99 вместо этого вы должны написать:
TEST_STRUCT test = {
.second = 2,
.first = 1
};
Этот синтаксис не определен стандартом C. Раздел 6.7.8 Initialization
говорит
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier
Если ваш компилятор принимает обозначение с двоеточием без диагностического сообщения, это означает, что ваш компилятор не (или не настроен) не соответствует стандартам.