Инициализация структуры 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 в Интернете. Кто-нибудь знает, как/почему это работает?


person Andrew Cottrell    schedule 21.10.2009    source источник


Ответы (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 };

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

Ваш компилятор должен иметь аналогичную документацию.

person sigjuice    schedule 21.10.2009
comment
Отлично, эта документация ясно объясняет синтаксис: Другой синтаксис, который имеет то же значение, устарел с GCC 2.5, это `fieldname:', как показано здесь: struct point p = { y: yvalue, x: xvalue }; - person Andrew Cottrell; 21.10.2009
comment
@AndrewCottrell, этот синтаксис fieldname: выглядит для меня таким естественным (и предпочтительным), есть идеи, почему его следует считать устаревшим? - person rick; 12.06.2017
comment
@rick имя поля: синтаксис является расширением gcc и никогда не был частью какого-либо стандарта ISO C. - person sigjuice; 12.06.2017

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

Это синтаксис для инициализации членов структуры, восходящий к дням до 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 };
person ndim    schedule 21.10.2009
comment
Да, я знал о назначенном формате инициализатора. К сожалению, этот формат несовместим с C++! (Во всяком случае, не в моем тестировании.) Спасибо за ответ. Хорошо, что это не стандартизировано. - person Andrew Cottrell; 21.10.2009
comment
@ Эндрю, ты ничего не сказал о C ++ в своем вопросе. - person horseyguy; 17.12.2009

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

person bk.    schedule 21.10.2009
comment
Альтернативный синтаксис (с использованием двоеточий) кажется мне таким естественным и предпочтительным, не могли бы вы пояснить, почему мы должны перейти на использование точек вместо двоеточий? - person rick; 12.06.2017

На самом деле это не «помеченные операторы», а способ задать начальные значения именованным полям в структуре.

Gcc выдает предупреждение об «устаревшем использовании назначенного инициализатора с ':'», а в C99 вместо этого вы должны написать:

    TEST_STRUCT test = {
        .second = 2,
        .first =  1
    };
person Thomas Padron-McCarthy    schedule 21.10.2009

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

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

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

person pmg    schedule 21.10.2009