¿Qué sucede si defino una matriz de 0 tamaños en C / C ++?

Solo curiosidad, lo que sucede realmente si defino una matriz int array[0]; longitud cero int array[0]; ¿en codigo? GCC no se queja en absoluto.

Progtwig de muestra

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

Aclaración

De hecho, estoy tratando de averiguar si las matrices de longitud cero inicializadas de esta manera, en lugar de apuntar como la longitud variable en los comentarios de Darhazer, están optimizadas o no.

Esto es porque tengo que liberar algún código en la naturaleza, así que estoy tratando de averiguar si tengo que manejar casos donde el SIZE se define como 0 , lo que sucede en algún código con una int array[SIZE]; definida estáticamente int array[SIZE];

De hecho, me sorprendió que GCC no se queje, lo que llevó a mi pregunta. De las respuestas que he recibido, creo que la falta de una advertencia se debe principalmente a la compatibilidad con el código antiguo que no se ha actualizado con la nueva syntax [].

Como principalmente me preguntaba sobre el error, estoy etiquetando la respuesta de Lundin como correcta (la de Nawaz fue la primera, pero no fue tan completa); los otros señalaron su uso real para las estructuras acolchadas por la cola, aunque son relevantes, no lo son. t exactamente lo que estaba buscando.

Una matriz no puede tener un tamaño cero.

ISO 9899: 2011 6.7.6.2:

Si la expresión es una expresión constante, tendrá un valor mayor que cero.

El texto anterior es verdadero tanto para una matriz simple (párrafo 1). Para un VLA (conjunto de longitud variable), el comportamiento no está definido si el valor de la expresión es menor o igual a cero (párrafo 5). Este es el texto normativo en el estándar C Un comstackdor no puede implementarlo de manera diferente.

gcc -std=c99 -pedantic da una advertencia para el caso que no es VLA.

Normalmente, no está permitido.

Sin embargo, ha sido una práctica habitual en C utilizar matrices flexibles .

C99 6.7.2.1, §16 : como un caso especial, el último elemento de una estructura con más de un miembro nombrado puede tener un tipo de matriz incompleto; esto se llama un miembro de matriz flexible.

Demostración:

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

La idea es que luego lo asignes así:

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

También puede usarlo estáticamente (extensión gcc):

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

Esto también se conoce como estructuras de cola acolchada (este término es anterior a la publicación del estándar C99) o struct hack (gracias a Joe Wreschnig por señalarlo).

Sin embargo, esta syntax se estandarizó (y los efectos se garantizaron) solo recientemente en C99. Antes era necesario un tamaño constante.

  • 1 era el modo portátil de ir, aunque era bastante extraño
  • 0 fue mejor para indicar intención, pero no fue legal en lo que respecta al estándar y fue respaldado como una extensión por algunos comstackdores (incluido gcc)

La práctica de relleno de cola, sin embargo, se basa en el hecho de que el almacenamiento está disponible ( malloc cuidadoso) por lo que no es adecuado para el uso de la stack en general.

En Standard C y C ++, no se permite array de tamaño cero.

Si está utilizando GCC, -pedantic con la opción -pedantic . Dará una advertencia , diciendo:

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

En el caso de C ++, da una advertencia similar.

Es totalmente ilegal, y siempre lo ha sido, pero muchos comstackdores se olvidan de señalar el error. No estoy seguro de por qué quieres hacer esto. El único uso que conozco es desencadenar un error de tiempo de comstackción de un booleano:

 char someCondition[ condition ]; 

Si la condition es falsa, entonces obtengo un error de tiempo de comstackción. Debido a que los comstackdores lo permiten, empecé a usar:

 char someCondition[ 2 * condition - 1 ]; 

Esto da un tamaño de 1 o -1, y nunca he encontrado un comstackdor que acepte un tamaño de -1.

Añadiré que hay una página completa de la documentación en línea de gcc en este argumento.

Algunas citas:

Arrays de longitud cero están permitidos en GNU C.

En ISO C90, tendrías que dar a los contenidos una longitud de 1

y

Las versiones de GCC anteriores a la 3.0 permitían que las matrices de longitud cero se inicializaran estáticamente, como si fueran matrices flexibles. Además de aquellos casos que fueron útiles, también permitió inicializaciones en situaciones que podrían corromper datos posteriores

para que pudieras

 int arr[0] = { 1 }; 

y bum 🙂

Las declaraciones de matriz de tamaño cero dentro de las estructuras serían útiles si estuvieran permitidas, y si la semántica fuera tal que (1) forzarían la alineación pero no asignarían ningún espacio, y (2) indexar la matriz se consideraría comportamiento definido en el caso donde el puntero resultante estaría dentro del mismo bloque de memoria que la estructura. Tal comportamiento nunca fue permitido por ningún estándar C, pero algunos comstackdores anteriores lo permitieron antes de que se convirtiera en estándar para que los comstackdores permitieran declaraciones de matriz incompletas con corchetes vacíos.

El struct hack, comúnmente implementado usando una matriz de tamaño 1, es dudoso y no creo que haya ningún requisito de que los comstackdores se abstengan de romperlo. Por ejemplo, esperaría que si un comstackdor ve int a[1] , estaría dentro de sus derechos considerar a[i] como a[0] . Si alguien intenta solucionar los problemas de alineación del struct hack a través de algo así como

 typedef struct {
   uint32_t tamaño;
   uint8_t data [4];  // Usa cuatro, para evitar que el relleno elimine el tamaño de la estructura
 }

un comstackdor podría ser inteligente y asumir que el tamaño de la matriz realmente es cuatro:

 ;  Como esta escrito
   foo = myStruct-> data [i];
 ;  Según lo interpretado (suponiendo hardware little-endian)
   foo = ((* (uint32_t *) myStruct-> data) >> (i << 3)) & 0xFF;

Tal optimización podría ser razonable, especialmente si myStruct->data podría cargarse en un registro en la misma operación que myStruct->size . No sé nada en el estándar que prohíba tal optimización, aunque, por supuesto, rompería cualquier código que pueda tener acceso a cosas que vayan más allá del cuarto elemento.

Otro uso de matrices de longitud cero es para hacer objetos de longitud variable (pre-C99). Las matrices de longitud cero son diferentes de las matrices flexibles que tienen [] sin 0.

Citado de gcc doc :

Los arrays de longitud cero están permitidos en GNU C. Son muy útiles como el último elemento de una estructura que realmente es un encabezado para un objeto de longitud variable:

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

En ISO C99, usaría un miembro de matriz flexible, que es ligeramente diferente en syntax y semántica:

  • Los miembros flexibles de la matriz se escriben como contenidos [] sin el 0.
  • Los miembros flexibles de la matriz tienen un tipo incompleto, por lo que no se puede aplicar el tamaño del operador.

Un ejemplo del mundo real son las matrices de longitud cero de struct kdbus_item en kdbus.h (un módulo kernel de Linux).