Pregunta

Estoy portando una aplicación a una plataforma ARM en C, la aplicación también se ejecuta en un procesador X86 y debe ser compatible con retroceso.

Ahora tengo algunos problemas con la alineación variable. He leído el manual de GCC para__attribute__((aligned(4),packed)) Interpreto lo que se dice como el comienzo de la estructura está alineado con el límite de 4 bytes y el interior permanece intacto debido a la declaración llena.

Originalmente tenía esto, pero ocasionalmente se coloca sin allinearse con el límite de 4 bytes.

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

Así que lo cambio a esto.

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((aligned(4),packed)) CHALLENGE;

La comprensión que declaré anteriormente parece ser incorrecta ya que tanto la estructura ahora está alineada con un límite de 4 bytes, y los datos internos ahora están alineados con un límite de cuatro bytes, pero debido a la endianess, el tamaño de la estructura ha aumentado en Tamaño de 42 a 44 bytes. Este tamaño es crítico ya que tenemos otras aplicaciones que dependen de que la estructura sea 42 bytes.

¿Podrían algunos describirme cómo realizar la operación que necesito? Cualquier ayuda es muy apreciada.

¿Fue útil?

Solución

Si depende de sizeof(yourstruct) Al ser 42 bytes, estás a punto de ser mordido por un mundo de supuestos no portátiles. No ha dicho para qué es esto, pero parece probable que la endianismo del contenido de la estructura también sea importante, por lo que también puede tener un desajuste con el X86 allí también.

En esta situación, creo que la única forma segura de hacer frente es usar unsigned char[42] en las partes donde importa. Comience escribiendo una especificación precisa de exactamente qué campos están en este bloque de 42 bytes y qué endian, luego use esa definición para escribir algún código para traducir entre eso y una estructura con la que puede interactuar. Es probable que el código sea el código de serialización de todo a la vez (también conocido como Marshalling) o un montón de Getters and Setters.

Otros consejos

Esta es una razón por la cual leer estructuras enteras en lugar de miembros falla, y debe evitarse.

En este caso, empacar más alinearse en 4 significa que habrá dos bytes de relleno. Esto sucede porque el tamaño debe ser compatible para almacenar el tipo en una matriz con todos los elementos aún alineados en 4.

Imagino que tienes algo como:

read(fd, &obj, sizeof obj)

Debido a que no desea leer esos 2 bytes de relleno que pertenecen a diferentes datos, debe especificar el tamaño explícitamente:

read(fd, &obj, 42)

Que puede mantener mantenible:

typedef struct {
  //...
  enum { read_size = 42 };
} __attribute__((aligned(4),packed)) CHALLENGE;

// ...

read(fd, &obj, obj.read_size)

O, si no puede usar algunas características de C ++ en su C:

typedef struct {
  //...
} __attribute__((aligned(4),packed)) CHALLENGE;
enum { CHALLENGE_read_size = 42 };

// ...

read(fd, &obj, CHALLENGE_read_size)

En la próxima oportunidad de refactorización, le sugiero que comience a leer cada miembro individualmente, lo que puede encapsularse fácilmente dentro de una función.

¿Cuál es tu verdadero objetivo?

Si se trata de tratar con datos en un archivo o en el cable en un formato particular, lo que debe hacer es escribir algunas rutinas de mariscal/serialización que mueven los datos entre la estructura del compilador que representa cómo desea lidiar con los datos dentro del programa y una matriz de char que se ocupa de cómo se ven los datos en el cable/archivo.

Entonces, todo lo que debe tratarse con cuidado y posiblemente tener un código específico de la plataforma son las rutinas de mariscal. Y puede escribir algunas pruebas unitarias bonitas para asegurarse de que los datos organizados lleguen y desde la estructura correctamente, sin importar a qué plataforma pueda tener que portar hoy y en el futuro.

He estado moviendo estructuras de un lado a otro de Linux, Windows, Mac, C, Swift, Assembly, etc.

El problema no es que no se pueda hacer, el problema es que no puede ser perezoso y debe comprender sus herramientas.

No veo por qué no puedes usar:

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

pueden Úselo y no requiere ningún código especial o inteligente. Escribo mucho código que se comunica con el brazo. Las estructuras son las que hacen que las cosas funcionen. __attribute__ ((packed)) es mi amigo.

Las probabilidades de estar en un "mundo de dolor" son nulos si comprende lo que está sucediendo con ambos.

Finalmente, no puedo entender cómo obtienes 42 o 44. int es 4 nuestros 8 bytes (dependiendo del compilador). Eso pone el número en 16+16+2 = 34 o 32+16+2 = 50, suponiendo que esté realmente lleno.

Como digo, conocer sus herramientas es parte de su problema.

Supongo que el problema es que 42 no es divisible por 4, por lo que no se alinean si pone varias de estas estructuras consecutivas (por ejemplo, asignar memoria para varios de ellos, determinando el tamaño con sizeof). Tener el tamaño como 44 fuerza la alineación en estos casos como lo solicitó. Sin embargo, si el desplazamiento interno de cada miembro de la estructura sigue siendo el mismo, puede tratar la estructura de 44 bytes como si fuera 42 bytes (siempre que tenga cuidado de alinear los siguientes datos en el límite correcto).

Un truco para probar podría ser poner ambas cosas de estas estructuras dentro de un solo tipo de unión y solo use la versión de 42 bytes de cada uno de dichas uniones.

Como estoy usando Linux, lo he encontrado por echo 3 > /proc/cpu/alignment Me emitirá una advertencia y solucionará el problema de alineación. Este es un trabajo, pero es muy útil para localizar dónde las estructuras no están malinineadas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top