Явные индексы в литералах массива 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, но не С++.
Ответы
Ответ 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 и ее нет в С++.