Подтвердить что ты не робот

Явные индексы в литералах массива C?

В источнике ядра Linux есть много литералов массивов, таких как:

enum {
  FOO,
  BAR
};

static const char* const names[] = {
  [FOO] = "foo", /* wtf is this? */
  [BAR] = "bar",
};

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

Я не знаю фразу для поиска - что это называется? Какой стандарт определяет его? (Или это расширение GNU?) Могу ли я сделать это на С++ или просто C? Экспериментируя с gcc, я найду с приведенным выше в test.c,

$ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE

эти команды возвращают успех:

$ gcc -Wall -c test.c
$ gcc -Wall -c --std=c90 test.c
$ gcc -Wall -c --std=gnu90 test.c
$ gcc -Wall -c --std=iso9899:1990 test.c
$ gcc -Wall -c --std=c1x test.c

и эти команды терпят неудачу с различными жалобами на лямбда и operator=:

$ g++ -Wall -c test.c
$ g++ -Wall -c --std=c++98 test.c
$ g++ -Wall -c --std=gnu++98 test.c
$ g++ -Wall -c --std=c++0x test.c
$ g++ -Wall -c --std=gnu++0x test.c

Это говорит о том, что это действительно C (практически в любом диалекте), но не С++. Но я настроен скептически. Я не помню, чтобы это использовалось где угодно, кроме ядра Linux. Я также не вижу в нем, например, этого списка конструкций, действительных в C, но не С++.

4b9b3361

Ответ 1

Это часть стандарта C (C99 и новее), называемая "назначенная инициализация".

От 6.7.9 Инициализация, пункт 6:

Если обозначение имеет вид

[ constant-expression ]

тогда текущий объект... должен иметь тип массива, и выражение должно быть целочисленным постоянным выражением. Если массив неизвестного размера, любое неотрицательное значение действительно.

И пункт 33:

ПРИМЕР 9 Массивы могут быть инициализированы для соответствия элементам перечисления с помощью указателей:

enum { member_one, member_two };
const char *nm[] = {
      [member_two] = "member two",
      [member_one] = "member one",
};

В соответствии с ответами на этот вопрос, С++ не поддерживает одно и то же поведение. Ваш компилятор может предоставить расширения.

Возможно, вам более полезно (и прямой ответ на ваш вопрос) является документация GCC, в которой говорится:

В ISO C99 вы можете указать элементы в любом порядке, указав индексы массива или имена полей структуры, к которым они применяются, и GNU C разрешает это как расширение в режиме C90. Это расширение не реализовано в GNU С++.

Ответ 2

Это инициализатор обозначения c99.

Инициализаторы инициализации позволяют инициализировать массив или структуру в любом порядке. Пропущенные элементы инициализируются так, как если бы они были статическими объектами.

int bla[16] = {[5] = 42, [9] = 42};

это инициализирует элемент bla[5] и bla[9] до 42, а все остальные элементы - 0. Обозначение представляет собой целочисленное постоянное выражение между [].

enum {
  FOO,
  BAR
};

static const char* const names[] = {
  [FOO] = "foo", /* wtf is this? */
  [BAR] = "bar",
};

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

Эта функция является функцией C и ее нет в С++.