Зачем нужны пустые скобки '{}' в конце массива структур?

59

Я ударил некоторых код в ядре Linux:

static struct ctl_table ip_ct_sysctl_table[] = {
    {
        .procname   = "ip_conntrack_max",
        .maxlen     = sizeof(int),
        .mode       = 0644,
        .proc_handler   = proc_dointvec,
    },
    // ...
    {
        .procname   = "ip_conntrack_log_invalid",
        .maxlen     = sizeof(unsigned int),
        .mode       = 0644,
        .proc_handler   = proc_dointvec_minmax,
        .extra1     = &log_invalid_proto_min,
        .extra2     = &log_invalid_proto_max,
    },
    { }
};

Здесь массив структур заканчивается { } . Для чего это было добавлено?
Кстати, чуть выше этого кода есть еще один массив структур , но без пустых скобок в конце.

Когда я должен использовать пустые скобки в конце массива структур?

NK-клетки
источник
1
Хм, а что если он добавлен, чтобы сигнализировать конец массива, как 0, сигнализировать конец строки? Просто угадай.
Эраклон
4
Это какое-то нестандартное расширение GCC. И как таковой, он, скорее всего, поставляется с небольшим количеством документации или вообще без нее ... Я просто прочитал все документы и не могу найти ничего о пустых списках инициализатора структуры. Тем не менее, он компилируется, если вы не используете строгий ISO -pedantic.
Лундин
9
В любом случае, это значение «часовой», элемент со всем, установленным в ноль / NULL, чтобы отметить конец массива.
Лундин
Часовые также распространены в модулях расширения CPython .
MaxPowers

Ответы:

38

Это конкретное изменение было частью сети sysctl: удалите неиспользованный двоичный код sysctl, принятый Эриком Бидерманом, изменив инициализацию последнего элемента ip_ct_sysctl_tableмассива с {0}на {}(и выполняет аналогичные изменения для многих других инициализаций массива).

{0}Картина , кажется, был гораздо дольше , хотя, и оба {0}или {}последний элемент-инициализации обычно (в исходном коде Linux) явно упоминается как Terminating entry, так что, вероятно , картина присутствует , чтобы потреблять эти массивы , не зная их длины, прекращение потребления при попадании в инициализируемую нулем завершающую запись. Например, для подобных массивов в целях sound/aoa/fabrics/snd-aoa-fabric-layout.cинициализации нуля даже явно упоминается в комментарии, например:

static struct codec_connection toonie_connections[] = {
  {
      .connected = CC_SPEAKERS | CC_HEADPHONE,
      .codec_bit = 0,
  },
  {} /* terminate array by .connected == 0 */
};
dfri
источник
11
Было бы интересно узнать их обоснование отказа от стандартного C в пользу расширения GCC, которое на 100% эквивалентно с точки зрения функциональности. Все, что он делает - это предотвращает компиляцию кода на стандартных компиляторах Си. То есть, предположительно, на 100% эквивалентно, потому что gcc, похоже, не документирует эту функцию ... Это не массив нулевой длины, это пустой список инициализатора.
Лундин
@Lundin не будет int arr[] = {}(учитывая, что мы используем пустое расширение инициализатора GNU) привести к пустому массиву; т.е. размерarr существа 0?
dfri
1
@Lundin: Страница cppreference, однако, противоречит формулировке ISO / IEC 9899: 2011, которая допускает это (§6.7.9 (21)). Нет инициализаторов, несомненно, «меньше», чем члены совокупности. Так что это не странное расширение компилятора, а законное C.
Damon
2
@ Damon Это недопустимый C и он хорошо известен ... компилировать с помощью gcc -pedantic-errors. Чтобы понять почему, вам нужно прочитать фактический синтаксис для списка инициализатора, вершина 6.7.9. Должен быть хотя бы один инициализатор. Объясняется здесь: stackoverflow.com/questions/17589533/… . В частности, { initializer-list }список инициализаторов: designation(opt) initializerилиinitializer-list , designation(opt) initializer
Лундин
2
@Lundin В этом конкретном случае, понятия не имею. Но расширения gcc широко используются в ядре Linux.
Бобсбернер
20

Вы, вероятно, знакомы с завершенными нулями строками. ctl_table ip_ct_sysctl_table[]является массивом с нулевым символом в конце, то есть последняя запись массива имеет все элементы с нулем.

MSalters
источник
1
Проходя через массив, вы знаете, что достигли конца, когда, например procname, maxlenноль или ноль.
Пол Огилви
1
@PaulOgilvie: Ну, пример не полный. procnameможет быть, char[100]в этом случае это ""не ноль. Но в остальном да.
MSalters
13

Зачем нужны пустые скобки '{}' в конце массива структур?

Для ясности: «пустые скобки» {} 'в конце массива структур »не нужны для удовлетворения требований синтаксиса C.

Когда я должен использовать пустые скобки в конце массива структур?

Когда код хочет дозорного значения .

Иногда для программы полезно иметь конечный элемент массива всех нулей - конечно, чтобы определить конец. Необходимость исходит от использования приложения массива ctl_table ip_ct_sysctl_table[], а не от необходимости языка C.

Chux - Восстановить Монику
источник
9

Это один нулевой инициализированный элемент в конце массива, чтобы увеличить количество элементов массива на один.

Рассмотрим это небольшое демо:

#include <stdio.h>

struct Test
{
  int x;
  int y;
} arr[] =
{
    {1,2},
    {3,4},
//  {}
};

int main(void) {
    printf("%zu\n", sizeof(arr) / sizeof(arr[0]));
    return 0;
}

Размер arrмассива изменится, если вы раскомментируете{} в конце списка инициализации массива.

Выходы:

С // {}(массив имеет 2 элемента)

2

С {}(массив имеет 3 элемента)

3

Дальнейшее объяснение:

ip_ct_sysctl_tableМассив используется только в одном месте, то есть здесь:

in->ctl_table = kmemdup(ip_ct_sysctl_table,
                sizeof(ip_ct_sysctl_table),
                GFP_KERNEL);

Дополнительно {}увеличивает общий размер ip_ct_sysctl_table.

бессмыслица
источник
1
Это не «для того, чтобы увеличить количество элементов массива», а чтобы сигнализировать конец массива.
Пол Огилви
6
Хах нет. Идея состоит в том, что до сих пор никто не смог объяснить это полностью, с абсолютной уверенностью. Ближайшее утверждение определенности состоит в том, что { }это инициализатор. Но почему до сих пор неясно. Таким образом, на данный момент, во всяком случае, слово, вероятно, является хорошей идеей. :)
рэйкер