Яка потреба порожніх дужок '{}' в кінці масиву структур?


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,
    },
    { }
};

Тут закінчується масив структур { }. З якою метою його додавали?
До речі, трохи вище цього коду є ще один масив структур , але без порожніх дужок в кінці.

Коли я повинен використовувати порожні дужки в кінці масиву структур?


1
Хм, що якщо він доданий, щоб сигналізувати про кінець масиву, як 0, сигналізувати про кінець рядка? Просто здогадуюсь.
Ераклон

4
Це деяке нестандартне розширення GCC. І як такий, він, ймовірно, має мало документації або взагалі не має ... Я просто прочитав усі документи і нічого не можу знайти про порожні списки ініціалізаторів структури. І все-таки він компілюється, якщо тільки не застосовувати суворі ISO -pedantic.
Лундін

9
У будь-якому випадку це значення "дозорного", елемент із усім, що встановлено на нуль / NULL, щоб позначити кінець масиву.
Лундін

Sentinels також поширені в модулях розширення 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 */
};

11
Було б цікаво знати їх обґрунтування відмови від стандарту C на користь розширення GCC, що 100% еквівалентно з точки зору функціональності. Все, що він робить - це запобігання компіляції коду на стандартних компіляторах C. Тобто, нібито на 100% еквівалент, тому що gcc, схоже, не документує цю функцію ... Це не масив нульової довжини, це порожній список ініціалізатора.
Лундін

@Lundin не хотів int arr[] = {}(враховуючи, що ми використовуємо порожнє розширення ініціалізатора GNU) не призведе до порожнього масиву; тобто розмір arrбуття 0?
dfri

1
@Lundin: Сторінка cppreference, однак, суперечить формулюванню ISO / IEC 9899: 2011, що дозволяє це (§ 6.7.9 (21)). Жоден ініціалізатор не безсумнівно "менший", ніж члени сукупності. Тож це не розширення для компілятора queer, а законне C.
Деймон

2
@Damon Це неправда C, і це добре відомо ... компілювати з gcc -pedantic-помилками. Щоб зрозуміти чому, вам потрібно прочитати власне синтаксис списку ініціалізатора, вгорі 6.7.9. Повинно бути принаймні один ініціалізатор. Пояснено тут: stackoverflow.com/questions/17589533/… . Зокрема, { initializer-list }тоді список ініціалізаторів: designation(opt) initializerабоinitializer-list , designation(opt) initializer
Лундін

2
@Lundin У цьому конкретному випадку, ідеї немає. Але розширення gcc широко використовуються в ядрі Linux.
bobsburner

20

Напевно, ви знайомі з нульовими завершеними рядками. ctl_table ip_ct_sysctl_table[]є нульовим завершеним масивом, тобто останній запис масиву має всі нульові члени.


1
Отже, проходячи через масив, ви знаєте, що ви досягли кінця, коли напр. procnameNull, або maxlenдорівнює нулю.
Пол Огільві

1
@PaulOgilvie: Ну, приклад неповний. У цьому випадку це procnameможе бути, а не нуль. Але інакше так. char[100]""
MSalters

13

Яка потреба порожніх дужок '{}' в кінці масиву структур?

Щоб було зрозуміло: "порожні дужки" {} "в кінці масиву структур" не потрібні для задоволення вимог синтаксису C.

Коли я повинен використовувати порожні дужки в кінці масиву структур?

Коли код бажає дозорне значення .

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


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
LOL, ні. Ідея полягає в тому, що поки що ніхто не зміг пояснити це повністю, з абсолютною впевненістю. Найближче твердження визначеності - це просто { }ініціалізатор. Але чому все ще незрозуміло. Таким чином, наразі все-таки це слово, мабуть , гарна ідея. :)
ryyker
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.