2009-12-21 2 views
5

내 데이터 (사용자 지정 구조체 모음 등)를 이진 파일에 저장하는 C++ 라이브러리를 작성했습니다. Windows (XP) 컴퓨터에서 로컬로 파일을 사용합니다 (예 : 사용 :). 단순화를 위해 작가 (파일을 만듭니다) 및 독자 또는 소비자 (파일에서 데이터를 읽는 것)의 두 부분으로 라이브러리를 생각해보십시오. 이진 파일 및 플랫폼 간 호환

최근하지만, 나는 또한 내 리눅스 시스템에서 내 XP 컴퓨터에 내가 을 만든 (즉, 읽기) 데이터 파일을 소비하고 싶습니다. 나는이 단계에서 두 기계가 모두 PC라는 것을 지적해야한다. (그래서 endianess 등이있다.)

필자는 라이브러리 작성자이므로 독자 (Linux [Ubuntu 9.10]를 정확하게 컴파일하십시오)를 만들 수 있습니다. 나는 (독자 등 건물)이 길을 착수하기 전에 내 질문입니다 :

했다 파일이에을 만들어, 내가 성공적으로

은 단순히 전체의 복사 할 수, 리눅스의 리더를 내장 한 가정 Windows (XP) 컴퓨터를 Linux (Ubuntu 9.10) 컴퓨터로 옮기고 Linux 판독기를 사용하여 성공적으로 복사 한 파일을 읽으십시오. 파일에 대한

+0

"바이너리 파일"이 의미하는 것을 좀 더 정의해야합니다. 'fwrite'를 사용하여'struct' 데이터 같은 것을 쓰는가? 모든 것을 바이트로 분해 한 다음 데이터를 씁니까? –

+1

모든 신발은 무엇인가요? 당신은 ** 강조 **에 별표를 사용할 수 있으며 더 읽기 쉽습니다 ... – danio

+0

@danio 그는 도데체에서 모든 것이 대문자 인 곳입니다 – zeitue

답변

14

바이너리 호환 될 수 있도록 : (당신을 위해처럼)

  • 엔디안
  • 비트 필드 패킹 순서가 동일해야합니다 종류의 같은
  • 크기와 부호의 수 있어야 일치해야합니다
  • 컴파일러는 그것은 확실히 가능 F의 패딩과 정렬

에 대해 같은 결정을해야합니다 또는 이러한 모든 조건이 충족되어야합니다. 그렇지 않은 경우에는 어떤 경우든지 치지 마십시오. 최소한, 문제를 감지하기 위해 몇 가지 정신 테스트 및/또는 감시 멤버를 추가 할 것입니다.

+0

안녕하세요 moonshadow, 의견에 감사드립니다. std :: vector가 포함 된 간단한 클래스를 사용하여 시간이있을 때 더 자세히 설명해 주시겠습니까 나는 정신 테스트 및/또는 감시 멤버가 의미하는 바를 분명하게 이해할 수 있습니다. limits.h에 정의 된 상수를 사용하여 이러한 검사를 구현하는 방법을 생각해 볼 수 있습니다. - 아니면 좀 더 우아한 접근 방식을 가지고 있습니까? –

+0

또한 요구 사항 2, 3 및 4 (위에 나열한 내용)가 사실인지 확인하는 방법을 잘 모르겠습니다. XP에서 VS2008을 사용하고 우분투에서 gcc 4.4.1을 사용하여 빌드합니다. 이러한 요구 사항을 위반하지 않았는지 확인할 수있는 방법은 무엇입니까? –

+2

@Stick it : "sentinel members"는 파일에 쓰여진 최상위 레벨 구조를 알고 상수 값을 가진 멤버를 포함하도록 정렬하는 것을 의미하며 파일의 끝에 하나도 배치합니다. 로드 할 때,이 멤버들이 기대하는 값을 포함하고 있는지 확인하십시오 - 이것은 컴파일러간에 다른 크기/패딩의 문제를 잡아야합니다. – moonshadow

2

이진 파일은 동일한 엔디안이있는 시스템에서 호환되어야합니다.

코드에서 발생할 수있는 문제는 int 크기이므로 다른 OS의 컴파일러가 같은 크기의 int를 사용한다고 가정 할 수는 없습니다. 그러니 바이트의 블록을 복사하여 캐스트, 또는 사용 INT16은 INT32 등

1

경우

  • 기계가 같은 엔디안이 (당신은 그들이 가지고 언급 한 바와 같이) 및
  • 당신은 열 할 텍스트 모드가 재미있는 일을 할 수 있기 때문에 바이너리 모드의 스트림 당신은 정렬, 데이터 타입의 크기 및 구조체 포장처럼 구현 정의 물건을 보려고하지 않도록 라인 끝과
  • 당신은

하는 것은 다음 네, 파일을 휴대해야 깨끗하게 프로그램했다.

세 번째 글 머리 기호는 파일 형식을 "휴대용"형식으로 만드는 것입니다. 구조체에있는 데이터의 종류에 따라 매우 쉽거나 약간 까다 롭습니다. 비트 필드 또는 다른 유형에서 재 해석되는 데이터는 특히 까다 롭습니다.

1

Boost Serialization Library을 살펴보십시오. 많은 생각이 들었으며, 잠재적 인 여러 플랫폼 간 비 호환성 문제를 처리 할 것입니다. 물론, 특히 독자가 이미 독자가 구현 한 & 독자를 구현 한 경우, 특정 사용 사례에 과도한 부담이 될 수 있습니다.

1

구조체는 이 아니고 파일 형식이이므로 이러한 형식으로 사용하지 마십시오.

freadfwrite으로 구조체를 만들려고 할 때 작동하도록 해킹 할 수있는 엄청난 양의 해킹이 있습니다. 당신은 리틀 엔디안과 빅 엔디 언 머신간에 파일을 공유 할 수 있도록 정수를 바이트 스왑합니다. 구조체를 고정 너비 정수 유형을 사용하도록 변경하여 다른 단어 크기 (예 : x86 및 x64 시스템) 사이에서 시스템간에 공유 할 수 있습니다. 컴파일러 버전간에 공유 할 구조체의 패딩을 제어하는 ​​컴파일러 관련 pragma를 추가합니다.

작동하지만 추한 것입니다. 말할 필요도없이, 잘못되기 쉽습니다.

The byte order fallacy의 권장 사항과 마찬가지로 훨씬 더 좋은 아이디어는 필드를 개별적으로 읽고 쓸 수있는 코드를 작성하는 것입니다. 자신 만의 코드를 작성하여 패딩이 없음을 보장 할 수 있으며 정수의 로컬 크기와 독립적으로 정수 크기를 선택할 수 있으며 바이트 스와핑없이 (정수 바이트를 별도로 읽거나 쓰는 방식으로) 두 엔디안을 모두 지원할 수 있습니다.

hacky 접근 방식과 달리 이것은 잘못 이해하기가 어렵습니다. 또한 컴파일러 나 아키텍처 관련 동작에 의존하지 않으므로 코드가 모든 컴파일러 및 아키텍처에서 작동하거나 전혀 작동하지 않습니다. 제대로한다면 플랫폼 관련 버그가 없어야합니다.

하나의 단점이 있습니다. 개별적으로 필드를 읽거나 쓰는 것은 fread/fwrite를 직접 사용하는 것보다 느려집니다. 버퍼 (uint8_t buffer[])를 설정하고 데이터 전체를 한 번에 쓰면 도움이 될 수 있지만 여전히 느리게 진행됩니다 (필드를 버퍼는 한 번에 하나씩), 대부분의 경우 아직 충분히 빠르다. (예외는 임베디드/실시간 시스템 또는 극도의 고성능 컴퓨팅이다.)

관련 문제