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?


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 */
};

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.


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.


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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.