Pergunta

Eu estou tentando escrever uma extensão Python C que lê embalado dados binários (ele é armazenado como estruturas de estruturas) e, em seguida, analisa-lo em objetos Python. Tudo funciona como esperado em uma máquina de 32 bits (os arquivos binários são sempre escritos na arquitetura de 32 bits), mas não em uma caixa de 64 bits. Existe uma maneira "preferido" de fazer isso?


Seria um monte de código de post, mas como um exemplo:

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
 );

Agora, em um sistema de 32 bits isso funciona muito bem, mas em um 64 bit meus tamanhos time_t são diferentes (32bit vs 64 longs bit).


Porra, você pessoas são rápidos.

Patrick, eu originalmente começou a usar o pacote de struct, mas achei que apenas uma maneira de retardar para minhas necessidades. Além disso, eu estava à procura de uma desculpa para escrever uma extensão Python.

Eu sei que esta é uma pergunta estúpida, mas que tipos eu preciso que atente para?

Graças.

Foi útil?

Solução

Explicitamente especificar que tipos de dados (por exemplo inteiros) são 32-bit. Caso contrário, se você tem dois inteiros ao lado do outro quando você lê-los eles vão ser lido como um inteiro de 64 bits.

Quando você está lidando com as questões de plataforma cruzada, as duas principais coisas que atente para são:

  1. Bitness. Se os seus dados embalado é escrito com ints de 32 bits, em seguida, todo o seu código deve especificar explicitamente ints de 32 bits ao ler e escrita.
  2. ordem Byte. Se você mover seu código de chips Intel para PPC ou SPARC, a sua ordem de bytes será errado. Você vai ter que importar seus dados e, em seguida, byte-lançá-lo para que ele combina com a arquitetura atual. Caso contrário, 12 (0x0000000C) será lido como 201326592 (0x0C000000).

Esperemos que esta ajuda.

Outras dicas

O módulo 'struct' deve ser capaz de fazer isso, embora o alinhamento de estruturas no meio dos dados é sempre um problema. Não é muito difícil de acertar, no entanto: descobrir (uma vez) que boundary as estruturas-em-estruturas alinhar para, em seguida, pad (manualmente, com o 'x' especificador) para esse limite. Você pode reverificar o seu preenchimento, comparando struct.calcsize () com o seu real dos dados. É certamente mais fácil do que escrever uma extensão de C para ele.

A fim de continuar usando Py_BuildValue () como esse, você tem duas opções. Você pode determinar o tamanho do time_t na compiletime (em termos de tipos fundamentais, então 'um int' ou 'muito' ou 'um ssize_t') e, em seguida, usar o caractere formato certo para Py_BuildValue - 'i' para um int, 'l' por um longo, 'n' para um ssize_t. Ou você pode usar PyInt_FromSsize_t () manualmente, caso em que o compilador faz o upcasting para você e, em seguida, usar os caracteres de formato 'O' para passar o resultado para Py_BuildValue.

Você precisa ter certeza de que você está usando arquitetura membros independentes para o seu struct. Por exemplo um int pode ser de 32 bits em uma arquitectura e 64 bits no outro. Como já foi sugerido, use os tipos de estilo int32_t vez. Se a sua estrutura contém membros não alinhados, você pode precisar para lidar com estofamento adicionado pelo compilador também.

Outro problema comum com os dados arquitetura cruz é endianness. Intel i386 arquitetura é little-endian, mas se você está lendo em uma máquina completamente diferente (por exemplo, um Alpha ou Sparc), você vai ter que se preocupar com isso também.

Os Python módulo struct lida com estas duas situações, usando o prefixo passado como parte da cadeia de formato.

  • @ - Use nativa tamanho, endianness e alinhamento. i = sizeof (int), L = sizeof (long)
  • = - Uso endianness nativa, mas tamanhos padrão e alinhamento (i = l, 32 bits = 64 bits)
  • <- Little-endian tamanhos padrão / alinhamento
    • tamanhos padrão Big-endian / alinhamento

Em geral, se os dados passa fora de sua máquina, você deve pregar para baixo a ordenação eo formato de tamanho / estofo para algo específico - ie. usar "<" ou ">" como seu formato. Se você deseja lidar com isso em seu ramal C, você pode precisar adicionar algum código para lidar com isso.

O que é o código para a leitura dos dados binários? Certifique-se de que você está copiando os dados em tipos de tamanho adequado como int32_t em vez de apenas int.

Por que você não está usando o href="http://docs.python.org/lib/module-struct.html" rel="nofollow pacote struct ?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top