Pregunta

Estoy intentando escribir una extensión de Python C que lea datos binarios empaquetados (se almacenan como estructuras de estructuras) y luego los analiza en objetos de Python. Todo funciona como se esperaba en una máquina de 32 bits (los archivos binarios siempre se escriben en una arquitectura de 32 bits), pero no en una caja de 64 bits. ¿Hay un & Quot; preferido & Quot; forma de hacer esto?


Sería mucho código publicar pero como ejemplo:

struct
{
    WORD    version;
    BOOL    upgrade;
    time_t  time1;
            time_t  time2;
} apparms;

File *fp;
fp = fopen(filePath, "r+b");
fread(&apparms, sizeof(apparms), 1, fp);
return Py_BuildValue("{s:i,s:l,s:l}",
  "sysVersion",apparms.version,
  "powerFailTime", apparms.time1,
  "normKitExpDate", apparms.time2
 );

Ahora en un sistema de 32 bits esto funciona muy bien, pero en 64 bits mis tamaños time_t son diferentes (32 bits frente a 64 bits de largo).


Maldición, ustedes son rápidos.

Patrick, originalmente comencé a usar el paquete de estructura, pero lo encontré de manera lenta para mis necesidades. Además, estaba buscando una excusa para escribir una extensión de Python.

Sé que esta es una pregunta estúpida, pero ¿qué tipos debo tener en cuenta?

Gracias.

¿Fue útil?

Solución

Especifique explícitamente que sus tipos de datos (por ejemplo, enteros) son de 32 bits. De lo contrario, si tiene dos enteros uno al lado del otro cuando los lea, se leerán como un entero de 64 bits.

Cuando se trata de problemas multiplataforma, las dos cosas principales a tener en cuenta son:

  1. Bitness. Si sus datos empaquetados se escriben con entradas de 32 bits, entonces todo su código debe especificar explícitamente entradas de 32 bits al leer y escribir.
  2. Orden de bytes. Si mueve su código de chips Intel a PPC o SPARC, su orden de bytes será incorrecta. Tendrá que importar sus datos y luego voltearlos en bytes para que coincida con la arquitectura actual. De lo contrario, 12 (0x0000000C) se leerá como 201326592 (0x0C000000).

Espero que esto ayude.

Otros consejos

El módulo 'struct' debería poder hacer esto, aunque la alineación de las estructuras en el medio de los datos siempre es un problema. Sin embargo, no es muy difícil hacerlo bien: descubra (una vez) a qué límite se alinean las estructuras en estructuras, luego rellene (manualmente, con el especificador 'x') a ese límite. Puede volver a verificar su relleno comparando struct.calcsize () con sus datos reales. Sin duda es más fácil que escribir una extensión C para él.

Para seguir usando Py_BuildValue () así, tiene dos opciones. Puede determinar el tamaño de time_t en tiempo de compilación (en términos de tipos fundamentales, por lo que 'an int' o 'a long' o 'an ssize_t') y luego usar el carácter de formato correcto para Py_BuildValue - 'i' para un int, 'l' por un largo, 'n' para un ssize_t. O puede usar PyInt_FromSsize_t () manualmente, en cuyo caso el compilador realiza la conversión por usted, y luego usar los caracteres de formato 'O' para pasar el resultado a Py_BuildValue.

Debe asegurarse de utilizar miembros independientes de la arquitectura para su estructura. Por ejemplo, un int puede tener 32 bits en una arquitectura y 64 bits en otra. Como otros han sugerido, use los tipos de estilo int32_t en su lugar. Si su estructura contiene miembros no alineados, es posible que también deba lidiar con el relleno agregado por el compilador.

Otro problema común con los datos de arquitectura cruzada es el endianness. La arquitectura Intel i386 es little-endian, pero si está leyendo en una máquina completamente diferente (por ejemplo, una Alpha o Sparc), también tendrá que preocuparse por esto.

El módulo de estructura Python trata estas dos situaciones, utilizando el prefijo pasado como parte de la cadena de formato.

  • @ - Usa tamaño nativo, endianness y alineación. i = sizeof (int), l = sizeof (largo)
  • = - Utilice endianness nativo, pero tamaños y alineación estándar (i = 32 bits, l = 64 bits)
  • < - Tamaños / alineación estándar Little-endian
  •   
        
    • Tamaños / alineación estándar Big-endian
    •   

En general, si los datos pasan de su máquina, debe precisar la endianidad y el formato de tamaño / relleno a algo específico & # 8212; es decir. use " < " o " > " como su formato Si desea manejar esto en su extensión C, es posible que deba agregar algún código para manejarlo.

¿Cuál es su código para leer los datos binarios? Asegúrese de copiar los datos en tipos de tamaño adecuado como int32_t en lugar de solo int.

¿Por qué no está utilizando el paquete struct ?

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