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

StackOverflow https://stackoverflow.com/questions/1601201

Вопрос

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

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

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

Это было полезно?

Решение

Вот раздел руководства по 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. Он не стандартизирован, но доступен, например, НКА.

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 Инициализация говорит

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top