Czego potrzeba pustych nawiasów klamrowych „{}” na końcu tablicy struktur?

59

Uderzyłem trochę kodu w jądrze Linuksa:

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

Tutaj kończy się tablica struktur { }. W jakim celu został dodany?
Nawiasem mówiąc, nieco powyżej tego kodu znajduje się kolejna tablica struktur , ale na końcu bez pustych nawiasów klamrowych.

Kiedy powinienem używać pustych nawiasów klamrowych na końcu tablicy struktur?

Komórka NK
źródło
1
Hmm, co jeśli dodane, aby zasygnalizować koniec tablicy jak 0, oznacza koniec łańcucha? Tylko zgaduję.
Eraklon
4
To jest jakieś niestandardowe rozszerzenie GCC. W związku z tym najprawdopodobniej zawiera niewielką lub żadną dokumentację ... Właśnie przeczytałem wszystkie dokumenty i nie mogę znaleźć niczego na temat pustych list inicjalizujących struktury. Jednak kompiluje się, chyba że wymusisz ścisłe ISO -pedantic.
Lundin
9
W każdym razie jest to wartość „wartownika”, element ze wszystkim ustawionym na zero / NULL, oznaczającym koniec tablicy.
Lundin
Sentinele są również powszechne w modułach rozszerzających CPython .
MaxPowers

Odpowiedzi:

38

Ta szczególna zmiana była częścią sieci sysctl: Usuń nieużywany binarny kod sysctl zatwierdzony przez Erica W. Biedermana, zmieniając inicjalizację ostatniego elementu ip_ct_sysctl_tabletablicy z {0}na{} (i wykonuje podobne zmiany w stosunku do wielu innych inicjalizacji tablicy).

{0}Wzór wydaje się, że już na znacznie dłużej, choć i zarówno {0}lub {}końcowy element inicjujący jest powszechnie (w kodzie źródłowym Linux) wyraźnie dalej Terminating entry, więc jest prawdopodobne, obecny wzór, aby umożliwić spożywanie tych tablic nie znając ich długości, zużycie końcowe po trafieniu w zainicjowany przez zero wpis zakończenia. Np. Dla podobnych tablic w sound/aoa/fabrics/snd-aoa-fabric-layout.ccelu zerowej inicjalizacji jest nawet wyraźnie wspomniane w komentarzu, np .:

static struct codec_connection toonie_connections[] = {
  {
      .connected = CC_SPEAKERS | CC_HEADPHONE,
      .codec_bit = 0,
  },
  {} /* terminate array by .connected == 0 */
};
dfri
źródło
11
Interesujące byłoby poznanie ich uzasadnienia dla odrzucenia standardowego C na korzyść rozszerzenia GCC, które jest w 100% równoważne pod względem funkcjonalności. Jedyne, co robi, to zapobiega kompilacji kodu w standardowych kompilatorach C. To znaczy podobno w 100% równoważne, ponieważ gcc wydaje się nie dokumentować tej funkcji ... To nie jest tablica o zerowej długości, to pusta lista inicjalizująca.
Lundin
@Lundin Nie dałby int arr[] = {}(biorąc pod uwagę, że używamy pustego rozszerzenia inicjującego GNU) pustej tablicy; tzn. wielkość arrbytu 0?
dfri
1
@Lundin: Strona preferencji jest jednak sprzeczna z brzmieniem normy ISO / IEC 9899: 2011, która to dopuszcza (§6.7.9 (21)). Żaden inicjator nie jest bez wątpienia „mniejszy” niż członkowie agregatu. Więc to nie jest rozszerzenie kompilatora queer, ale uzasadnione C.
Damon
2
@Damon Nie jest poprawny C i jest dobrze znany ... kompiluj z gcc -pedantic-error. Aby zrozumieć dlaczego, musisz przeczytać aktualną składnię listy inicjalizacyjnej, na początku 6.7.9. Musi być co najmniej jeden inicjator. Wyjaśnione tutaj: stackoverflow.com/questions/17589533/... . W szczególności { initializer-list }lista inicjatorów: designation(opt) initializerlubinitializer-list , designation(opt) initializer
Lundin
2
@Lundin W tym konkretnym przypadku nie ma pojęcia. Ale rozszerzenia gcc są szeroko stosowane w jądrze Linuksa.
Spalacz
20

Prawdopodobnie znasz ciągi zerowane. ctl_table ip_ct_sysctl_table[]jest tablicą zakończoną zerem, tzn. ostatnia pozycja tablicy ma elementy całkowicie zerowe.

MSalters
źródło
1
Przechodząc przez tablicę, wiesz, że dotarłeś do końca, gdy np. Ma procnamewartość zero lub maxlenzero.
Paul Ogilvie
1
@PaulOgilvie: Cóż, przykład jest niekompletny. procnamemoże być char[100]w takim przypadku "", a nie zerowy. Ale poza tym tak.
MSalters
13

Czego potrzeba pustych nawiasów klamrowych „{}” na końcu tablicy struktur?

Żeby było jasne: „puste nawiasy klamrowe {}” na końcu tablicy struktur ”nie są potrzebne do spełnienia wymagań składni C.

Kiedy powinienem używać pustych nawiasów klamrowych na końcu tablicy struktur?

Gdy kod chce wartości wartownika .

Czasami przydatne jest, aby program miał końcowy element tablicy zawierający wszystkie zera - z pewnością do wykrycia końca. Potrzeba wynika z zastosowania aplikacji tablicy ctl_table ip_ct_sysctl_table[], nie z potrzeby języka C.

chux - Przywróć Monikę
źródło
9

Jest to jeden element inicjowany zerem na końcu tablicy, aby zwiększyć liczbę elementów tablicy o jeden.

Rozważ to małe demo:

#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;
}

Rozmiar arrtablicy zmieni się, jeśli usuniesz zaznaczenie {}na końcu listy inicjalizacji tablicy.

Wyjścia:

Z // {}(tablica ma 2 elementy)

2

Z {}(tablica ma 3 elementy)

3

Dalsze wyjaśnienia:

ip_ct_sysctl_tableTablica jest używana tylko w jednym miejscu, które jest tutaj:

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

Dodatkowy {}zwiększa całkowity rozmiar ip_ct_sysctl_table.

Jabberwocky
źródło
1
To nie jest „w celu zwiększenia liczby elementów tablicy”, ale w celu zasygnalizowania końca tablicy.
Paul Ogilvie
6
Haha nie. Chodzi o to, że jak dotąd nikt nie był w stanie wyjaśnić tego całkowicie, z absolutną pewnością. Najbliższym stwierdzeniem pewności jest po prostu, że { }jest to inicjator. Ale dlaczego wciąż nie jest jasne. Tak więc, na razie tak, słowo prawdopodobnie jest dobrym pomysłem. :)
ryyker