C struct инициализация с использованием меток. Это работает, но как? - PullRequest
39 голосов
/ 21 октября 2009

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

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 ]

36 голосов
/ 21 октября 2009

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

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

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

33 голосов
/ 21 октября 2009

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

Это синтаксис для инициализации членов структуры, начиная с дней до 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 };
11 голосов
/ 21 октября 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, о котором я могу думать, так как он является стандартом. Обидно, что они не так известны.

5 голосов
/ 21 октября 2009

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

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

    TEST_STRUCT test = {
        .second = 2,
        .first =  1
    };
3 голосов
/ 21 октября 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...