Qual è la necessità di parentesi graffe vuote '{}' alla fine della matrice di strutture?


59

Ho colpito un po 'di codice nel kernel di 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,
    },
    { }
};

Qui termina una serie di strutture { }. Per quale scopo è stato aggiunto?
A proposito, un po 'sopra questo codice c'è un altro array di strutture , ma senza parentesi graffe vuote alla fine.

Quando dovrei usare le parentesi graffe vuote alla fine di una serie di strutture?


1
Cosa succede se viene aggiunto per segnalare la fine dell'array come 0 segnala la fine della stringa? Tiravo a indovinare.
Eraklon

4
Questa è un'estensione GCC non standard. E come tale, molto probabilmente viene fornito con poca o nessuna documentazione ... Ho appena letto tutti i documenti e non riesco a trovare nulla sugli elenchi di inizializzatori struct vuoti. Eppure si compila, a meno che non si imponga ISO severi -pedantic.
Lundin

9
Ad ogni modo, si tratta di un valore "sentinella", un elemento con tutto impostato su zero / NULL per contrassegnare la fine dell'array.
Lundin

Le sentinelle sono anche comuni nei moduli di estensione CPython .
MaxPowers il

Risposte:


38

Questa particolare modifica faceva parte della rete sysctl: rimuove il commit del codice sysctl binario non utilizzato da Eric W. Biederman, cambiando l'inizializzazione dell'ultimo elemento ip_ct_sysctl_tabledell'array da {0}a {}(ed esegue modifiche simili a molte altre inizializzazioni dell'array).

Il {0}modello sembra essere stato in giro per molto più tempo, però, e sia {0}o {}elemento di inizializzazione finale è comunemente (nel codice sorgente di Linux) esplicitamente indicato come Terminating entry, per cui è probabile un modello attuale per permettere di consumare questi array senza conoscere la loro lunghezza, consumo finale quando si colpisce la voce di chiusura zero inizializzata. Ad esempio per matrici simili sound/aoa/fabrics/snd-aoa-fabric-layout.cnell'intento di inizializzare lo zero viene anche esplicitamente menzionato in un commento, ad esempio:

static struct codec_connection toonie_connections[] = {
  {
      .connected = CC_SPEAKERS | CC_HEADPHONE,
      .codec_bit = 0,
  },
  {} /* terminate array by .connected == 0 */
};

11
Sarebbe interessante conoscere la loro logica per far cadere lo standard C a favore di un'estensione GCC che è equivalente al 100% in termini di funzionalità. Tutto ciò che impedisce è la compilazione del codice su compilatori C standard. Cioè, presumibilmente equivalente al 100% perché gcc non sembra documentare questa funzione ... Questo non è un array di lunghezza zero, è un elenco di inizializzatori vuoto.
Lundin

@Lundin Non darebbe int arr[] = {}(dato che stiamo usando l'estensione di inizializzazione vuota GNU) in un array vuoto; cioè, le dimensioni arrdell'essere 0?
venerdì

1
@Lundin: La pagina di cppreference è comunque in conflitto con la formulazione ISO / IEC 9899: 2011, che lo consente (§6.7.9 (21)). Nessun inizializzatore è senza dubbio "meno" dei membri dell'aggregato. Quindi questa non è un'estensione del compilatore queer, ma legittima C.
Damon

2
@Damon Non è valido C ed è ben noto ... compilare con errori gped -pedantic. Per capire il motivo, è necessario leggere la sintassi effettiva per un elenco di inizializzatori, all'inizio del 6.7.9. Deve esserci almeno un inizializzatore. Spiegato qui: stackoverflow.com/questions/17589533/… . In particolare, { initializer-list }quindi elenco di inizializzazione: designation(opt) initializeroinitializer-list , designation(opt) initializer
Lundin

2
@Lundin In questo caso specifico, non ne ho idea. Ma le estensioni gcc sono ampiamente utilizzate nel kernel di Linux.
Bobsburner

20

Probabilmente hai familiarità con le stringhe con terminazione zero. ctl_table ip_ct_sysctl_table[]è un array con terminazione zero, ovvero l'ultima voce dell'array ha membri zero.


1
Quindi, passando attraverso l'array, sai di aver raggiunto la fine quando, ad esempio, procnameè null o maxlenè zero.
Paul Ogilvie il

1
@PaulOgilvie: bene, l'esempio è incompleto. procnamepotrebbe essere un char[100]nel qual caso è "", non null. Ma per il resto sì.
MSalters il

13

Qual è la necessità di parentesi graffe vuote '{}' alla fine della matrice di strutture?

Per essere chiari: i "parentesi graffe vuote" {} "alla fine della matrice di strutture" non sono necessari per soddisfare i requisiti della sintassi C.

Quando dovrei usare le parentesi graffe vuote alla fine di una serie di strutture?

Quando il codice vuole un valore sentinella .

A volte è utile che il programma abbia un elemento array finale di tutti gli zeri, sicuramente per rilevare la fine. La necessità deriva dall'uso dell'array da parte dell'applicazione ctl_table ip_ct_sysctl_table[], non da un'esigenza del linguaggio C.


9

È un elemento zero inizializzato alla fine della matrice per aumentare di uno il numero di elementi della matrice.

Considera questa piccola 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;
}

La dimensione arrdell'array cambierà se si decommenta il {}alla fine dell'elenco di inizializzazione dell'array.

Uscite:

Con // {}(l'array ha 2 elementi)

2

Con {}(l'array ha 3 elementi)

3

Ulteriori spiegazioni:

L' ip_ct_sysctl_tablearray viene utilizzato solo in un posto, ovvero qui:

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

Il supplemento {}aumenta la dimensione totale ip_ct_sysctl_table.


1
Questo non è "per aumentare il numero di elementi dell'array" ma per segnalare la fine dell'array.
Paul Ogilvie,

6
LOL no. L'idea è che nessuno finora è stato in grado di spiegarlo completamente, con assoluta certezza. La dichiarazione di certezza più vicina è semplicemente che { }è un inizializzatore. Ma il perché non è ancora chiaro. Quindi, per ora comunque, la parola probabilmente è probabilmente una buona idea. :)
Ryker
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.