ProgramaciónDesarrollador C embebido/bajo nivel

Explique cómo funcionan las uniones (union) en el lenguaje C. ¿Qué problemas resuelven, cómo se usan correctamente y cuáles son las trampas típicas que se encuentran al usarlas?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

Union (unión) es un tipo de dato especial que almacena diferentes valores en la misma área de memoria. En una union, todos los miembros se ubican en la memoria en la misma dirección, y el volumen de memoria es igual al tamaño del miembro más grande.

Uso:

  • Es conveniente para ahorrar memoria, si una variable en un momento dado puede tomar uno de varios tipos de valores;
  • Permite interpretar los mismos bits de diferentes maneras (por ejemplo, para acceso a bajo nivel o protocolos).

Ejemplo:

union Data { int i; float f; char s[4]; }; union Data d; d.i = 0x41424344; // ahora en memoria hay 4 bytes que se pueden leer como int, float, cadena printf("%c%c%c\n", d.s[0], d.s[1], d.s[2]); // salida específica del proveedor

Trampas y reglas de uso:

  • Mantenga en la unión solo un "campo significativo" a la vez.
  • No hay un seguimiento automático de qué campo fue el "activo" último.
  • Leer un campo no activo es comportamiento indefinido.
  • ¡El orden de los bytes en la plataforma es muy importante (endian!)!

Pregunta trampa

Pregunta: ¿Cuál es el sentido de usar una unión cuando se puede simplemente usar una estructura con varios campos?

Respuesta: El uso de una unión ahorra memoria, ya que en cualquier momento solo se almacena UN valor dentro, no todos a la vez. En una estructura, se asigna memoria para cada campo, mientras que en una unión solo se asigna para el máximo de los campos, y los otros "comparten" esta memoria. También la unión permite realizar conversiones seguras o intencionadas entre diferentes representaciones de datos en un mismo fragmento de memoria.

Ejemplo:

struct S { int i; float f; } s; // sizeof = sizeof(int) + sizeof(float) union U { int i; float f; } u; // sizeof = max(sizeof(int),sizeof(float))

Ejemplos de errores reales


Historia

En el proyecto de un controlador de dispositivo, la comunicación con el "hardware" se realizaba a través de una unión con acceso a los bits de los datos. Después de una pequeña refactorización, el desarrollador comenzó a escribir en el campo incorrecto de la unión, lo que llevó a la lectura de datos no actuales y fallos fatales del sistema, porque en la unión solo un campo es "real" en cada momento.


Historia

Al intercambiar paquetes de red a través de una unión para gestionar la memoria, el desarrollador olvidó tener en cuenta la alineación de las estructuras. Como resultado, hubo un desplazamiento de un byte, y la estructura se parseaba con desplazamientos incorrectos, lo que hacía que el protocolo fuera incompatible con el original.


Historia

Al trabajar en una biblioteca de serialización, el programador pasó la unión por valor a una función, donde no se inicializaba el campo necesario antes de la lectura. Debido a esto, los datos se serializaban incorrectamente, aparecían residuos en el flujo de salida y no se podía recuperar la información original.