variable structs initialize example array c

initialize - structs in java



C struct hackear en el trabajo (4)

¿Es así como se puede usar la memoria "extra" asignada al usar la estructura C hack?

Preguntas:

Tengo una implementación de C struct hack a continuación. Mi pregunta es cómo puedo usar la memoria "extra" que he asignado con el truco. ¿Puede alguien darme un ejemplo sobre el uso de esa memoria extra?

#include<stdio.h> #include<stdlib.h> int main() { struct mystruct { int len; char chararray[1]; }; struct mystruct *ptr = malloc(sizeof(struct mystruct) + 10 - 1); ptr->len=10; ptr->chararray[0] = ''a''; ptr->chararray[1] = ''b''; ptr->chararray[2] = ''c''; ptr->chararray[3] = ''d''; ptr->chararray[4] = ''e''; ptr->chararray[5] = ''f''; ptr->chararray[6] = ''g''; ptr->chararray[7] = ''h''; ptr->chararray[8] = ''i''; ptr->chararray[9] = ''j''; }


Desde que leí este artículo ( http://blogs.msdn.com/b/oldnewthing/archive/2004/08/26/220873.aspx ), me ha gustado usar la estructura hackear así:

#include<stdio.h> #include<stdlib.h> int main() { struct mystruct { int len; char chararray[1]; }; int number_of_elements = 10; struct mystruct *ptr = malloc(offsetof(struct mystruct, chararray[number_of_elements])); ptr->len = number_of_elements; for (i = 0; i < number_of_elements; ++i) { ptr->chararray[i] = ''a'' + i; } }

Encuentro que no tener que recordar si es necesario restar 1 (o agregarlo o lo que sea) es bueno. Esto también tiene la ventaja de trabajar en situaciones donde se usa 0 en la definición de matriz, que no todos los compiladores admiten, pero algunos sí lo hacen. Si la asignación se basa en offsetof() , no tiene que preocuparse por los posibles detalles que hacen que su matemática sea incorrecta.

También funciona sin cambios si la estructura es un miembro de matriz flexible C99.


Es "correcto", pero necesitaría una buena razón para hacerlo sobre una solución más razonable. Es más común que usen esta técnica para "superponer" alguna matriz existente para imponerle algún tipo de estructura de encabezado.

Tenga en cuenta que GCC por extensión permite un miembro de la matriz de longitud cero exactamente para este propósito, mientras que ISO C99 "legitima" la práctica al permitir a un miembro con corchetes vacíos (solo como el último miembro).

Tenga en cuenta que hay algunos problemas semánticos: el tamaño de la estructura, por supuesto, no tendrá en cuenta el tamaño "flexible" del miembro final, y pasar la estructura "por valor" solo pasará el encabezado y el primer elemento (o ningún elemento que use el GCC). extensión o miembro de matriz flexible C99). De manera similar, la asignación de estructura directa no copiará todos los datos.


Sí, esa es (y fue) la forma estándar en C para crear y procesar una struct tamaño variable.

Ese ejemplo es un poco detallado. La mayoría de los programadores lo manejarían más hábilmente:

struct mystruct { int len; char chararray[1]; // some compilers would allow [0] here }; char *msg = "abcdefghi"; int n = strlen (msg); struct mystruct *ptr = malloc(sizeof(struct mystruct) + n + 1); ptr->len = n; strcpy (ptr->chararray, msg); }


Yo recomendaría que, debido a posibles problemas de alineación, considere esto:

struct my_struct { char *arr_space; unsigned int len; } struct my_struct *ptr = malloc(sizeof(struct my_struct) + 10); ptr->arr_space = ptr + 1; ptr->len = 10;

Esto le dará tanto la ubicación como la seguridad :) y evitará problemas de alineación extraños.

Por problemas de alineación me refiero a posibles retrasos de acceso para acceder a la memoria no alineada.

En el ejemplo original, si agrega un byte o un miembro no alineado a la palabra (byte, char, short), entonces el compilador puede ampliar el tamaño de la estructura pero, en lo que respecta al puntero, está leyendo la memoria directamente después del final de la secuencia. estructura (no alineada). Esto significa que si tiene una matriz de un tipo alineado como, por ejemplo, cada acceso le proporcionará un impacto de rendimiento en las CPU que reciben resultados de la lectura de la memoria no alineada.

struct { byte_size data; char *var_len; some_align added by compiler; }

En el caso original, leerá de la región some_align , que es solo un relleno, pero en mi caso, leerá de la memoria adicional alineada posteriormente (lo que desperdicia espacio pero normalmente está bien).

Otra ventaja de hacer esto es que es posible obtener más localidades de las asignaciones asignando todo el espacio para miembros de longitud variable de una struct en una asignación en lugar de asignarlos por separado (evita los gastos generales de llamadas de asignación múltiple y le da cierta localidad de caché en lugar de rebotar) toda la memoria).