O que acontece se eu definir um array de tamanho 0 em C / C ++?

Apenas curioso, o que realmente acontece se eu definir um array de tamanho zero int array[0]; em código? O GCC não reclama nada.

Programa de Amostra

 #include  int main() { int arr[0]; return 0; } 

Esclarecimento

Na verdade, estou tentando descobrir se as matrizes de comprimento zero inicializadas dessa maneira, em vez de serem apontadas como a duração variável nos comentários de Darhazer, estão otimizadas ou não.

Isso é porque eu tenho que liberar alguns códigos para o estado selvagem, então estou tentando descobrir se tenho que lidar com casos em que o SIZE é definido como 0 , o que acontece em algum código com uma int array[SIZE]; definida estaticamente int array[SIZE];

Fiquei realmente surpreso que o GCC não reclame, o que levou à minha pergunta. Das respostas que recebi, acredito que a falta de um aviso é em grande parte devido ao suporte ao código antigo que não foi atualizado com a nova syntax [].

Como eu estava me perguntando principalmente sobre o erro, estou marcando a resposta de Lundin como correta (a de Nawaz foi a primeira, mas não foi tão completa) – os outros estavam apontando seu uso real para estruturas acolchoadas na cauda, ​​embora seja relevante. É exatamente o que eu estava procurando.

Uma matriz não pode ter tamanho zero.

ISO 9899: 2011 6.7.6.2:

Se a expressão é uma expressão constante, ela deve ter um valor maior que zero.

O texto acima é verdadeiro para um array simples (parágrafo 1). Para um VLA (array de comprimento variável), o comportamento é indefinido se o valor da expressão for menor ou igual a zero (parágrafo 5). Este é um texto normativo no padrão C. Um compilador não tem permissão para implementá-lo de forma diferente.

gcc -std=c99 -pedantic dá um aviso para o caso não-VLA.

Normalmente, isso não é permitido.

No entanto, tem sido prática atual em C usar matrizes flexíveis .

C99 6.7.2.1, §16 : Como um caso especial, o último elemento de uma estrutura com mais de um membro nomeado pode ter um tipo de matriz incompleta; isso é chamado de membro da matriz flexível.

Demonstração:

 struct Array { size_t size; int content[]; }; 

A ideia é que você aloque então:

 void foo(size_t x) { Array* array = malloc(sizeof(size_t) + x * sizeof(int)); array->size = x; for (size_t i = 0; i != x; ++i) { array->content[i] = 0; } } 

Você também pode usá-lo estaticamente (extensão gcc):

 Array a = { 3, { 1, 2, 3 } }; 

Isso também é conhecido como estruturas tail-padded (este termo é anterior à publicação do C99 Standard) ou struct hack (graças a Joe Wreschnig por apontá-lo).

No entanto, esta syntax foi padronizada (e os efeitos garantidos) apenas recentemente em C99. Antes que um tamanho constante fosse necessário.

  • 1 era o caminho portátil a seguir, embora fosse bastante estranho
  • 0 foi melhor em indicar intenção, mas não é legal no que diz respeito ao Standard e foi apoiado como uma extensão por alguns compiladores (incluindo o gcc)

A prática de preenchimento de rabo, no entanto, depende do fato de que o armazenamento está disponível ( malloc cuidado), portanto, não é adequado para o uso da pilha em geral.

No padrão C e C ++, matriz de tamanho zero não é permitida ..

Se você estiver usando o GCC, compile-o com a opção -pedantic . Isso dará aviso , dizendo:

zero.c:3:6: warning: ISO C forbids zero-size array 'a' [-pedantic]

No caso do C ++, ele fornece um aviso semelhante.

É totalmente ilegal, e sempre foi, mas muitos compiladores deixam de sinalizar o erro. Não sei por que você quer fazer isso. O único uso que eu conheço é para acionar um erro de tempo de compilation de um booleano:

 char someCondition[ condition ]; 

Se a condition for falsa, obtenho um erro de tempo de compilation. Porque compiladores permitem isso, no entanto, eu comecei a usar:

 char someCondition[ 2 * condition - 1 ]; 

Isso dá um tamanho de 1 ou -1, e eu nunca encontrei um compilador que aceita um tamanho de -1.

Eu adicionarei que há uma página inteira da documentação online do gcc neste argumento.

Algumas citações:

Matrizes de comprimento zero são permitidas no GNU C.

No ISO C90, você teria que dar um conteúdo de 1

e

As versões do GCC anteriores a 3.0 permitiam que as matrizes de comprimento zero fossem inicializadas estaticamente, como se fossem matrizes flexíveis. Além dos casos que eram úteis, também permitia inicializações em situações que corromperiam dados posteriores

então você poderia

 int arr[0] = { 1 }; 

e boom 🙂

Declarações de array de tamanho zero dentro de structs seriam úteis se fossem permitidas, e se as semânticas fossem tais que (1) forçariam o alinhamento mas não alocariam espaço algum, e (2) indexar o array seria considerado comportamento definido no caso em que o ponteiro resultante estaria dentro do mesmo bloco de memory que a estrutura. Esse comportamento nunca foi permitido por nenhum padrão C, mas alguns compiladores mais antigos permitiram que ele se tornasse padrão para compiladores para permitir declarações de matriz incompletas com colchetes vazios.

O struct hack, como comumente implementado usando uma matriz de tamanho 1, é desonesto e eu não acho que exista algum requisito que os compiladores evitem quebrá-lo. Por exemplo, eu esperaria que, se um compilador visse int a[1] , estaria dentro de seus direitos considerar a[i] como a[0] . Se alguém tentar resolver os problemas de alinhamento do struct hack através de algo como

 typedef struct {
   uint32_t size;
   dados do uint8_t [4];  // Use quatro, para evitar o preenchimento do tamanho da estrutura
 }

um compilador pode ficar esperto e assumir que o tamanho da matriz é realmente quatro:

 ;  Como escrito
   foo = myStruct-> data [i];
 ;  Conforme interpretado (assumindo hardware little-endian)
   foo = ((* (uint32_t *) myStruct-> data) >> (i << 3)) & 0xFF;

Essa otimização pode ser razoável, especialmente se os myStruct->data puderem ser carregados em um registrador na mesma operação que myStruct->size . Eu não sei nada no padrão que proíba essa otimização, embora, é claro, isso quebre qualquer código que possa esperar acessar coisas além do quarto elemento.

Outro uso de matrizes de comprimento zero é para fazer object de comprimento variável (pré-C99). Matrizes de comprimento zero são diferentes de matrizes flexíveis que possuem [] sem 0.

Citado do doc do gcc :

Arrays de comprimento zero são permitidos no GNU C. Eles são muito úteis como o último elemento de uma estrutura que é realmente um header para um object de comprimento variável:

  struct line { int length; char contents[0]; }; struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length); thisline->length = this_length; 

No ISO C99, você usaria um membro de matriz flexível, que é um pouco diferente em syntax e semântica:

  • Os membros flexíveis da matriz são gravados como conteúdo [] sem o 0.
  • Os membros flexíveis da matriz têm tipo incompleto e, portanto, o operador sizeof não pode ser aplicado.

Um exemplo do mundo real é uma matriz de comprimento zero de struct kdbus_item em kdbus.h (um módulo do kernel do Linux).

Intereting Posts