Qual é a necessidade de chaves vazias '{}' no final da matriz de estruturas?

59

Eu bati algum código no kernel do 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,
    },
    { }
};

Aqui, uma matriz de estruturas termina com { }. Para que finalidade foi adicionada?
A propósito, um pouco acima desse código, há outra matriz de estruturas , mas sem chaves vazias no final.

Quando devo usar chaves vazias no final de uma matriz de estruturas?

Célula NK
fonte
11
Hmm, e se fosse adicionado para sinalizar o final da matriz, como 0 sinaliza o final da string? Apenas adivinhando.
Eraklon
4
Essa é uma extensão não padrão do GCC. E, como tal, provavelmente vem com pouca ou nenhuma documentação ... Acabei de ler todos os documentos e não consigo encontrar nada sobre as listas vazias de inicializadores de estrutura. No entanto, ele compila, a menos que você force ISO estrito -pedantic.
Lundin
9
De qualquer forma, é um valor "sentinela", um item com tudo definido como zero / NULL para marcar o final da matriz.
Lundin
Sentinelas também são comuns nos módulos de extensão CPython .
MaxPowers

Respostas:

38

Essa alteração em particular fazia parte da rede sysctl: Remova o código binário sysctl não utilizado confirmado por Eric W. Biederman, alterando a inicialização do último elemento da ip_ct_sysctl_tablematriz de {0}para {}(e executa alterações semelhantes a muitas outras inicializações de matriz).

O {0}padrão parece existir há muito mais tempo, e a inicialização de ambos os elementos {0}ou {}final é comumente referida (no código-fonte do Linux) explicitamente referida como Terminating entry, portanto, é provável que haja um padrão presente para permitir o consumo dessas matrizes sem saber seus comprimentos, terminando o consumo ao pressionar a entrada de finalização inicializada com zero. Por exemplo, para matrizes semelhantes na sound/aoa/fabrics/snd-aoa-fabric-layout.cintenção da inicialização zero, é mencionado explicitamente em um comentário, por exemplo:

static struct codec_connection toonie_connections[] = {
  {
      .connected = CC_SPEAKERS | CC_HEADPHONE,
      .codec_bit = 0,
  },
  {} /* terminate array by .connected == 0 */
};
dfri
fonte
11
Seria interessante conhecer sua lógica de descartar o padrão C em favor de uma extensão do GCC que seja 100% equivalente em termos de funcionalidade. Tudo o que faz é impedir que o código seja compilado nos compiladores C padrão. Ou seja, supostamente 100% equivalente, porque o gcc não parece documentar esse recurso ... Esta não é uma matriz de comprimento zero, é uma lista de inicializadores vazia.
Lundin
@Lundin Não int arr[] = {}(dado que estamos usando a extensão do inicializador vazio GNU) resultaria em uma matriz vazia; ou seja, o tamanho do arrser 0?
dfri 02/03
11
@Lundin: No entanto, a página cppreference está em conflito com a redação da ISO / IEC 9899: 2011, que permite isso (§6.7.9 (21)). Nenhum inicializador é, sem dúvida, "menos" que os membros do agregado. Portanto, essa não é uma extensão de compilador estranho, mas C. legítima.
Damon
2
@ Damon Não é C válido e é bem conhecido ... compile com erros -pedantic-gcc. Para entender o porquê, você precisa ler a sintaxe real de uma lista de inicializadores, parte superior de 6.7.9. Deve haver pelo menos um inicializador. Explicado aqui: stackoverflow.com/questions/17589533/… . Especificamente, em { initializer-list }seguida, a lista de inicializadores: designation(opt) initializerouinitializer-list , designation(opt) initializer
Lundin
2
@ Lundin Neste caso específico, não faço ideia. Mas as extensões gcc são usadas extensivamente no kernel do linux.
bobsburner 03/03
20

Você provavelmente está familiarizado com cadeias terminadas em zero. ctl_table ip_ct_sysctl_table[]é uma matriz terminada com zero, ou seja, a última entrada da matriz possui membros com zero.

MSalters
fonte
11
Então, passando pela matriz, você sabe que chegou ao fim quando eg procnameé nulo ou maxlené zero.
Paul Ogilvie
11
@PaulOgilvie: Bem, o exemplo está incompleto. procnamepode ser um char[100]caso em que não é ""nulo. Mas caso contrário, sim.
MSalters
13

Qual é a necessidade de chaves vazias '{}' no final da matriz de estruturas?

Para ficar claro: o "colchetes vazios '{}' no final da matriz de estruturas" não é necessário para atender aos requisitos de sintaxe C.

Quando devo usar chaves vazias no final de uma matriz de estruturas?

Quando o código deseja um valor de sentinela .

Às vezes, é útil que o programa tenha um elemento final da matriz com todos os zeros - certamente para detectar o final. A necessidade vem do uso do array pelo aplicativo ctl_table ip_ct_sysctl_table[], não da necessidade da linguagem C.

chux - Restabelecer Monica
fonte
9

É um elemento inicializado com zero no final da matriz para aumentar o número de elementos da matriz em um.

Considere esta pequena demonstração:

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

O tamanho da arrmatriz será alterado se você descomentar {}no final da lista de inicialização da matriz.

Saídas:

With // {}(array possui 2 elementos)

2

With {}(array tem 3 elementos)

3

Mais explicações:

A ip_ct_sysctl_tablematriz é usada apenas em um local, aqui:

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

O extra {}aumenta o tamanho total ip_ct_sysctl_table.

Jabberwocky
fonte
11
Isso não é "para aumentar o número de elementos da matriz", mas para sinalizar o final da matriz.
Paul Ogilvie
6
Lol não. A idéia é que ninguém até agora foi capaz de explicá-lo completamente, com absoluta certeza. A afirmação mais próxima da certeza é simplesmente que { }é um inicializador. Mas o porquê ainda não está claro. Portanto, por enquanto, a palavra provavelmente é provavelmente uma boa ideia. :)
ryyker 02/03