Un tipo para memoria arbitraria en C

Esto es en referencia a esta pregunta.

¿Cómo implementar correctamente las funciones de c malloc / realloc?

donde la respuesta aceptada menciona que se puede usar una matriz char para modelar un grupo de memoria arbitraria.

Sin embargo, uno de los comentarios a esa respuesta aceptada dice:

Una matriz de caracteres que no tiene una duración de almacenamiento asignada solo puede tener un alias de un tipo de carácter. En otras palabras, no puede y no debe usarse como memoria arbitraria.

¿Es esto correcto? Si es así, entonces, ¿qué podría usarse? Me gustaría evitar el uso de alloc o cualquier llamada específica al sistema operativo, por lo que soy simétrico con esa pregunta.

Creo que el problema que señaló fue que si asigna una matriz de tipo char forma estática y luego comstack su biblioteca con un comstackdor de C moderno como escritorio, como gcc, no puede convertir fácilmente el contenido de esa área a otro tipo. Porque entonces el comstackdor realizaría optimizaciones basadas en el aliasing de punteros y arruinaría todo, vea “la regla estricta de aliasing” .

Simplemente asegúrate de que tu comstackdor no use un alias estricto y estarás bien. Por ejemplo, ninguno de los comstackdores de sistemas embebidos comunes en el mercado hace esto.

Con gcc comstackrías como -fno-strict-aliasing . Podría ser bueno habilitar siempre las advertencias para el código que causaría tales problemas.

Como nota al uint8_t , uint8_t tiene mucho más sentido utilizarlo como tipo genérico, porque a diferencia de char , es completamente inequívoco: no tiene firmeza y el tamaño es bien conocido.

Hay diferentes problemas alrededor. Primero, como lo muestra la respuesta de @Magisch, la pregunta relacionada fue devolver un puntero colgante que causa un comportamiento indefinido y generalmente errores de ejecución.

El segundo está relacionado con la regla estricta de aliasing @ ^ * # (censura aquí). Los comstackdores comunes producen el código correcto cuando utiliza una matriz de caracteres como un búfer grande para asignar cualquier tipo, siempre y cuando se asegure la alineación correcta. Después de todo, esta es la forma en que tienen que implementar las rutinas malloc , realloc y free . Y como son parte del entorno alojado (biblioteca estándar de C), los desarrolladores del comstackdor no son loo masocistas como para evitar ese uso.

Pero el estándar C es un poco más estricto aquí. Debería leer mi propia respuesta aquí para una pregunta similar y, en particular, para el comentario de @ EOF:

No puede plotr partes de un objeto declarado como char [] en objetos de otros tipos (excepto tipos de caracteres), porque tienen un tipo declarado … lo que significa que técnicamente no puede implementar malloc () en C puro

El alias se refiere a la regla de alias estricta que rige cómo el comstackdor puede usar registros. Si tiene punteros de diferente tipo que se refieren a la misma ubicación de memoria, entonces la escritura realizada a través de un tipo de puntero puede no notarse al leer a través del otro tipo de puntero porque el comstackdor puede almacenar en caché los datos en los registros.

Cuando implementas un grupo de memoria, este problema generalmente es discutible, porque la implementación del grupo no lee / escribe en la memoria.

Si quieres tipos arbitrarios, entonces la apuesta más segura es una unión. No solo “superará” la estricta regla de alias, sino que también garantizará la alineación correcta. Recuerde que malloc y sus amigos garantizan una alineación adecuada para cualquier tipo, mientras que el auto no lo hace.

El problema es la alineación. En los procesadores que tienen restricciones de alineación, es posible que una matriz de caracteres no se inicie en una dirección adecuada para almacenar objetos más grandes, como int o double .

Por lo tanto, para estar seguro, debe asegurarse de que la matriz char esté alineada correctamente para cualquier tipo. Si está utilizando un comstackdor C11, puede forzar una alineación como esta

 #include  #include  _Alignas(max_align_t) char buffer[SIZE]; 

Para comstackdores más antiguos, __attribute__((aligned(SIZE))) puede ser una solución. De lo contrario, debes buscar un #pragma que #pragma la alineación.

Y como se discutió en varios comentarios / respuestas, definitivamente debería deshabilitar la optimización de aliasing estricta con la -fno-strict-aliasing . Si esa opción (o su equivalente) no existe, entonces necesita determinar el nivel de optimización que se basa en la regla de alias estricta y solo usar un nivel de optimización más bajo.