Quel est le besoin d'accolades vides '{}' à la fin du tableau de structures?

59

J'ai frappé du code dans le noyau 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,
    },
    { }
};

Ici, un tableau de structures se termine par { }. Dans quel but a-t-il été ajouté?
Soit dit en passant, un peu au-dessus de ce code, il y a un autre tableau de structures , mais sans accolades vides à la fin.

Quand dois-je utiliser des accolades vides à la fin d'un tableau de structures?

Cellule NK
la source
1
Hmm que se passe-t-il s'il ajoute pour signaler la fin du tableau comme 0 signale la fin de la chaîne? Je devine.
Eraklon
4
Il s'agit d'une extension GCC non standard. Et en tant que tel, il vient très probablement avec peu ou pas de documentation ... Je viens de lire tous les documents et je ne trouve rien sur les listes d'initialisation de structure vides. Pourtant, il compile, sauf si vous forcez ISO strict avec -pedantic.
Lundin
9
Quoi qu'il en soit, il s'agit d'une valeur "sentinelle", un élément dont tout est réglé sur zéro / NULL pour marquer la fin du tableau.
Lundin
Les sentinelles sont également courantes dans les modules d'extension CPython .
MaxPowers

Réponses:

38

Cette modification particulière faisait partie du réseau sysctl: supprimer le code binaire sysctl inutilisé validé par Eric W. Biederman, en changeant l'initialisation du dernier élément du ip_ct_sysctl_tabletableau de {0}à{} (et effectuant des modifications similaires à de nombreuses autres initialisations de tableau).

Le {0}modèle semble avoir été bien plus longtemps que, et les deux {0}ou {}dernier élément initialisation est généralement (dans le code source Linux) fait explicitement référence comme Terminating entry, il est donc probable un cadeau de modèle pour permettre la consommation de ces tableaux sans connaître leurs longueurs, arrêt de la consommation lors de la saisie de l'entrée de fin initialisée à zéro. Par exemple, pour les tableaux similaires dans sound/aoa/fabrics/snd-aoa-fabric-layout.cl'intention de l'initialisation zéro est même explicitement mentionné dans un commentaire, par exemple:

static struct codec_connection toonie_connections[] = {
  {
      .connected = CC_SPEAKERS | CC_HEADPHONE,
      .codec_bit = 0,
  },
  {} /* terminate array by .connected == 0 */
};
dfri
la source
11
Il serait intéressant de connaître leur justification pour l'abandon de la norme C au profit d'une extension GCC 100% équivalente en termes de fonctionnalité. Tout ce qu'il fait est d'empêcher le code de compiler sur des compilateurs C standard. Autrement dit, 100% équivalent parce que gcc ne semble pas documenter cette fonctionnalité ... Ce n'est pas un tableau de longueur nulle, c'est une liste d'initialisation vide.
Lundin
@Lundin ne donnerait pas int arr[] = {}(étant donné que nous utilisons l'extension d'initialisation vide GNU) un tableau vide; c'est-à-dire la taille de l' arrêtre 0?
dfri
1
@Lundin: La page cppreference est cependant en conflit avec le libellé de l'ISO / IEC 9899: 2011, qui le permet (§6.7.9 (21)). Aucun initialiseur n'est sans aucun doute "moins" que les membres de l'agrégat. Ce n'est donc pas une extension de compilateur étrange, mais un C. légitime
Damon
2
@Damon Ce n'est pas un C valide et c'est bien connu ... compiler avec gcc -pedantic-errors. Pour comprendre pourquoi, vous devez lire la syntaxe réelle d'une liste d'initialisation, en haut de 6.7.9. Il doit y avoir au moins un initialiseur. Expliqué ici: stackoverflow.com/questions/17589533/… . Plus précisément, la { initializer-list }liste des initialiseurs: designation(opt) initializerouinitializer-list , designation(opt) initializer
Lundin
2
@Lundin Dans ce cas précis, aucune idée. Mais les extensions gcc sont largement utilisées dans le noyau Linux.
bobsburner
20

Vous connaissez probablement les chaînes terminées par zéro. ctl_table ip_ct_sysctl_table[]est un tableau terminé par zéro, c'est-à-dire que la dernière entrée du tableau a des membres entièrement nuls.

MSalters
la source
1
Donc, en parcourant le tableau, vous savez que vous avez atteint la fin lorsque, par exemple, procnameest nul ou maxlennul.
Paul Ogilvie
1
@PaulOgilvie: Eh bien, l'exemple est incomplet. procnamepourrait être un char[100]cas dans lequel il est "", non nul. Mais sinon oui.
MSalters
13

Quel est le besoin d'accolades vides '{}' à la fin du tableau de structures?

Pour être clair: les "accolades vides '{}' à la fin du tableau de structures" ne sont pas nécessaires pour satisfaire aux exigences de la syntaxe C.

Quand dois-je utiliser des accolades vides à la fin d'un tableau de structures?

Quand le code veut une valeur sentinelle .

Il est parfois utile pour le programme d'avoir un élément de tableau final de tous les zéros - certainement pour détecter la fin. Le besoin vient de l'utilisation du tableau par l'application ctl_table ip_ct_sysctl_table[], et non d'un besoin en langage C.

chux - Réintégrer Monica
la source
9

C'est un élément initialisé à zéro à la fin du tableau afin d'augmenter le nombre d'éléments du tableau de un.

Considérez cette petite démo:

#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 taille du arrtableau changera si vous décommentez le{} à la fin de la liste d'initialisation du tableau.

Les sorties:

Avec // {}(le tableau a 2 éléments)

2

Avec {}(le tableau a 3 éléments)

3

Plus d'explications:

Le ip_ct_sysctl_tabletableau n'est utilisé qu'à un seul endroit, c'est-à-dire ici:

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

Le supplément {}augmente la taille totale ip_ct_sysctl_table.

Jabberwocky
la source
1
Ce n'est pas "pour augmenter le nombre d'éléments du tableau" mais pour signaler la fin du tableau.
Paul Ogilvie
6
LOL, non. L'idée est que personne jusqu'à présent n'a été en mesure de l'expliquer complètement, avec une certitude absolue. La déclaration de certitude la plus proche est simplement que le { }est un initialiseur. Mais le pourquoi n'est toujours pas clair. Ainsi, pour l' instant de toute façon, le mot probablement est probablement une bonne idée. :)
ryyker