C инициализация структуры с использованием меток. Это работает, но как? Документация?

Я вчера нашел код инициализации структуры, который бросил меня на цикл. Вот пример:

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

Как вы можете видеть, структура получает правильную инициализацию. Я не знал, что обозначенные заявления могут быть использованы так. Я видел несколько других способов выполнения инициализации структуры, но я не нашел примеров такого рода инициализации структуры для любого из часто задаваемых вопросов в Интернете C. Кто-нибудь знает, как и почему это работает? Или документация о том, что это правильный синтаксис?

Ответ 1

Вот раздел руководства 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 };

Соответствующую страницу можно найти здесь.

У вашего компилятора должна быть схожая документация.

Ответ 2

Это не метки и битовые поля.

Это синтаксис для инициализации элементов структуры, относящихся ко времени, предшествующим C99. Он не является стандартизированным, но доступен, например, НКА.

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

Ответ 3

Да, как указано выше, это назначенные инициализаторы, которые являются стандартными 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, о котором я могу думать, будучи стандартом. Жаль, что они не так хорошо известны.

Ответ 4

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

Gcc дает предупреждение о "устаревшем использовании назначенного инициализатора с помощью::", а в C99 вы должны написать:

    TEST_STRUCT test = {
        .second = 2,
        .first =  1
    };

Ответ 5

Этот синтаксис не определен стандартом C. Раздел 6.7.8 Initialization говорит

         designation:
                designator-list =
         designator-list:
                designator
                designator-list designator
         designator:
                [ constant-expression ]
                . identifier

Если ваш компилятор принимает обозначение с двоеточием без диагностического сообщения, это означает, что ваш компилятор не настроен (или не настроен) Соответствие стандартам.