matrices de longitud cero [duplicate]

6 minutos de lectura

avatar de usuario
matiz

Recientemente me encontré con una definición de estructura,

struct arr {
    int cnt;
    struct {
        int  size;
        int *name;
    } list[0];
};

y ahora no se la razon de list[0] siendo declarado. Lo que me interesa es por qué se usa esto. ¿Tiene alguna ventaja? ¿Y si si, que?

  • Los objetos de tamaño cero son ilegales en C. Cualquiera de los dos usa [1] y desperdiciar un poco de espacio (o calcular para compensarlo), o usar [] (pero entonces su código requiere un compilador C99).

    – R.. GitHub DEJA DE AYUDAR A ICE

    14 de enero de 2011 a las 17:24

  • Aquí está la sección del manual de gcc sobre matrices de longitud cero: gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

    – Pierz

    29 de junio de 2016 a las 17:01

avatar de usuario
relajarse

El uso es para matrices de longitud dinámica. Puede asignar la memoria usando malloc()y haga que la matriz resida al final de la estructura:

struct arr *my_arr = malloc(sizeof *my_arr + 17 * sizeof *my_arr->list);
my_arr->cnt = 17;
my_arr->list[0].size = 0;
my_arr->list[1].name = "foo";

En realidad, poder usar 0 para la longitud es (como se señaló en un comentario) una extensión GCC. En C99, puede omitir el tamaño literal por completo para obtener el mismo efecto.

Antes de que se implementaran estas cosas, a menudo veía que esto se hacía con una longitud de 1, pero eso complica un poco la asignación, ya que debe compensar al calcular la memoria necesaria.

  • Para agregar a eso, siendo una matriz de longitud 0, list no contribuye al tamaño de la estructura. sizeof(struct arr) == 4

    –Jeff Mercado

    14 de enero de 2011 a las 11:56

  • La capacidad de usar una longitud 0 es una característica de GCC. El equivalente C99 es omitir la longitud por completo, como en struct { ... } list[];

    –Bart van Ingen Schenau

    14 de enero de 2011 a las 12:05

  • lista de estructura { int tamaño; int *nombre; }; struct arr { int cnt; estructura lista *list_ptr; }; esto es un equivalente?

    – matiz

    14 de enero de 2011 a las 12:34


  • @hue: no, eso tendría su matriz de lista almacenada y ubicada en otro lugar de la memoria. Esto tiene la lista inmediatamente después de la estructura.

    – jw

    14 de enero de 2011 a las 13:12

  • @hue: Er… Acabas de obtener dos respuestas que describen esa ventaja. Le permite asignar la memoria para la estructura y para la matriz de longitud variable al final de la estructura como un bloque de memoria continuacon una llamada a malloc. Si usó un puntero, tendría que asignar la memoria por separado (dos malloc llamadas, probablemente no continuas) o usar algunos otros trucos (para lograr una alineación adecuada, etc.)

    – Ant

    14 de enero de 2011 a las 18:12


avatar de usuario
Hormiga

Se llama “truco de estructura”. Puedes buscarlo en SO o en la Red

http://www.google.com/search?q=struct+hack&sitesearch=stackoverflow.com/questions

Tenga en cuenta que formalmente siempre es ilegal declarar matrices de tamaño 0 en C. El código que proporcionó formalmente ni siquiera es compilable. Sin embargo, la mayoría de los compiladores de C aceptarán la declaración de matriz de tamaño 0 como una extensión, específicamente porque a menudo se usa en la versión “perezosa” de “struct hack” (puede confiar en sizeof para determinar cuánta memoria asignar, ya que la matriz de tamaño 0 supuestamente no afecta el tamaño total de la estructura).

Podría decirse que una mejor implementación de struct hack utiliza una matriz de tamaño 1

struct arr {
    int cnt;
    struct {
        int  size;
        int *name;
    } list[1];
};

Es “mejor” porque al menos es formalmente compilable. Para asignar memoria para una estructura con N elementos en el listestándar offsetof se usa macro

arr *a = malloc(offsetof(arr, list) + N * sizeof a->list);

En la versión C99 de la especificación del idioma, el “truco de estructura” se admite a través de la declaración de matriz sin tamaño (con espacios vacíos). []), ya que las declaraciones de matriz de tamaño 0 también son ilegales en C99.

  • ¿Hay algo en el estándar que prohíba a un compilador que ve una declaración unsigned char foo[1]; de compilar todos los accesos a foo[x] como si fueran foo[0]? Si bien las personas que responden preguntas de “trucción de estructuras” consideran académica la cuestión de si la versión de matriz de tamaño 1 es un “comportamiento indefinido”, la optimización antes mencionada podría ser útil, especialmente en algunos contextos de sistemas integrados, si es legal. ¿Sería (agregando la advertencia de que un compilador podría querer deshabilitarlo explícitamente para el último elemento de una estructura a la que se accede indirectamente)?

    – Super gato

    13 de enero de 2012 a las 23:54

  • @supercat si entiendo tu pregunta, silenciosamente causaría un comportamiento extraño, que &(foo[999]) == &(foo[0]) por ejemplo. Se supone que un[b] === (&a[0])+b

    –Steven R. Loomis

    27 de febrero de 2013 a las 6:46

  • @StevenR.Loomis: La suposición que solo haces solo se mantiene si b es menor que el número de elementos en a. Si un puntero producido por una matriz dentro de una estructura solo puede indexarse ​​dentro de la menor de la matriz declarado tamaño o el espacio asignado, entonces el escenario que describe sería Comportamiento indefinido. Si estuviera a cargo de los estándares, especificaría que acceder a una matriz fuera de su rango especificado sería un comportamiento indefinido excepto en el caso específico de que una matriz de un solo elemento al final de una estructura pueda usar un índice distinto de cero si esa estructura es…

    – Super gato

    27 de febrero de 2013 a las 15:52

  • …el último elemento en una sección de la memoria recibida por malloc, callocetc. Tal regla requeriría que los compiladores continúen admitiendo el código antiguo usando el “truco de estructura”, pero permitiría la mayoría de las optimizaciones que permitiría la aplicación de matriz de estructura (solo el caso de un solo elemento que mencioné, pero también muchos otros escenarios que involucran aliasing, etc. Por ejemplo, dado struct {int a[1], b;} foo; foo.b=3; x=foo.a[something()]; foo.b=0; si se requiere que el compilador almacene el 3 en la memoria antes de acceder foo.a[]o debería permitirse omitir la tienda?

    – Super gato

    27 de febrero de 2013 a las 15:57

  • @supercat pero el tiempo de ejecución no sabe cuántos elementos hay “en” a, mi suposición fue solo una reafirmación de cómo entiendo C para interpretar los subíndices de la matriz. De hecho, diría que el escenario es un comportamiento definido (lo estoy utilizando en este momento). Ahora el valor de B[999] o b[-100] puede ser indefinido, pero el conducta Yo sostendría está definido. No esperaría que el compilador detecte errores de rango aquí.

    –Steven R. Loomis

    27 de febrero de 2013 a las 17:19

Otra ventaja es si su estructura describe datos en disco/en red. Si cnt es 0, el tamaño de los datos solo puede ser la longitud de cnt.

Estoy aquí solo para confirmar lo que temía, que list[0] no es válido.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad