64 비트 시스템에서 32 비트 포장 바이너리 데이터를 읽습니다
문제
나는 포장 된 이진 데이터를 읽는 Python C 확장을 작성하려고 시도하고있다 (스트러크의 스트러크로 저장됨). 모든 것이 32 비트 머신에서 예상대로 작동하지만 (이진 파일은 항상 32 비트 아키텍처에 작성) 64 비트 상자에는 그렇지 않습니다. 이 작업을 수행하는 "선호하는"방법이 있습니까?
게시해야 할 많은 코드이지만 예를 들어 :
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
);
이제 32 비트 시스템에서 이것은 훌륭하게 작동하지만 64 비트에서는 Time_t 크기가 다릅니다 (32 비트 대 64 비트 길이).
젠장, 당신은 빠릅니다.
패트릭, 나는 원래 구조물 패키지를 사용하기 시작했지만 내 필요에 따라 속도가 느려지는 것을 알았습니다. 게다가 나는 파이썬 확장을 쓸 변명을 찾고있었습니다.
나는 이것이 어리석은 질문이라는 것을 알고 있지만 어떤 유형을 조심해야합니까?
감사.
해결책
데이터 유형 (예 : 정수)이 32 비트임을 명시 적으로 지정합니다. 그렇지 않으면 읽을 때 서로 옆에 두 개의 정수가 있다면 64 비트 정수로 읽습니다.
크로스 플랫폼 문제를 다룰 때 조심해야 할 두 가지 주요 사항은 다음과 같습니다.
- 큰 소리. 포장 된 데이터가 32 비트 INT로 작성된 경우 읽을 때 모든 코드가 32 비트 int를 명시 적으로 지정해야합니다. 그리고 글쓰기.
- 바이트 순서. 코드를 인텔 칩에서 PPC 또는 SPARC로 옮기면 바이트 주문이 잘못됩니다. 현재 아키텍처와 일치하도록 데이터를 가져 와서 바이트 플립을해야합니다. 그렇지 않으면 12 (
0x0000000C
) 201326592로 읽습니다 (0x0C000000
).
바라건대 이것은 도움이됩니다.
다른 팁
데이터 중간에있는 스트러크의 정렬은 항상 문제가되지만 '구조'모듈은이를 수행 할 수 있어야합니다. 그러나 올바르게 얻는 것은 그리 어렵지 않습니다. (한 번) Structs-in-Structs가 어떤 경계를 정렬 한 다음, 그 경계에 패드 (수동으로 'x'지정자와 함께)를 찾으십시오. struct.calcsize ()를 실제 데이터와 비교하여 패딩을 이중화 할 수 있습니다. C 확장을 작성하는 것보다 확실히 쉽습니다.
이와 같은 Py_BuildValue ()를 계속 사용하려면 두 가지 옵션이 있습니다. 컴파일 타임 (기본 유형의 측면에서 'int'또는 'long'또는 'ssize_t')에서 time_t의 크기를 결정한 다음 올바른 형식 문자를 Py_BuildValue에 사용하여 int, int, int, 'i'에 올바른 형식 문자를 사용하십시오. 'l'는 ssize_t의 경우 'l', 'n'. 또는 pyint_fromssize_t ()를 수동으로 사용할 수 있으며,이 경우 컴파일러가 업 캐스트를 수행 한 다음 'O'형식 문자를 사용하여 결과를 py_buildValue에 전달합니다.
구조물에 아키텍처 독립 멤버를 사용하고 있는지 확인해야합니다. 예를 들어 INT는 한 아키텍처에서 32 비트, 다른 아키텍처에서 64 비트 일 수 있습니다. 다른 사람들이 제안한 것처럼 사용하십시오 int32_t
대신 스타일 유형. 구조물에 정렬되지 않은 멤버가 포함 된 경우 컴파일러가 추가 한 패딩을 처리해야 할 수도 있습니다.
교차 아키텍처 데이터의 또 다른 일반적인 문제는 Endianness입니다. 인텔 i386 아키텍처는 작은 엔디언이지만 완전히 다른 기계 (예 : 알파 또는 SPARC)를 읽고 있다면 이것에 대해서도 걱정해야합니다.
Python Struct 모듈은 형식 문자열의 일부로 전달 된 접두사를 사용하여 이러한 두 상황을 처리합니다.
- @- 기본 크기, 엔지니어 및 정렬을 사용하십시오. i = sizeof (int), l = sizeof (long)
- = - 기본 엔지니어를 사용하지만 표준 크기와 정렬 (i = 32 비트, L = 64 비트)
- < - 리틀 엔디안 표준 크기/정렬
- 빅 엔디안 표준 크기/정렬
일반적으로 데이터가 컴퓨터에서 전달되면 엔디 니스와 크기 / 패딩 형식을 구체적인 것으로 정신해야합니다. "<"또는 ">"을 형식으로 사용하십시오. C 확장 에서이를 처리하려면 처리하려면 코드를 추가해야 할 수도 있습니다.
이진 데이터를 읽기위한 코드는 무엇입니까? 데이터를 적절한 크기의 유형으로 복사하고 있는지 확인하십시오. int32_t
그냥 대신 int
.
왜 당신은 사용하지 않습니다 구조 패키지?