2016-12-24 1 views
5

바이너리 파일 유형 인 데이터베이스 파일 terminfo을 파싱합니다. 직접 storage format에 대해 읽고 내가 직면 한 문제를 확인할 수 있습니다.리틀 엔디안 읽기 16 비트 부호없는 정수

수동 말한다 -

헤더 섹션은 파일을 시작합니다. 이 섹션에는 6 개의 짧은 정수가 아래에 설명 된 형식으로 포함되어 있습니다. 이 정수는 다음과 같습니다.

(1) 매직 넘버 (8 진수 0432);

...

...

짧은 정수는 2 개의 8 비트 바이트에 저장됩니다. 첫 번째 바이트는 값의 최하위 8 비트 인 을 포함하고 두 번째 바이트는 최상위 8 비트를 포함합니다. (따라서 표현 된 값은 256 * second + first입니다.) 값 -1은 2 바이트 0377, 0377로 표시됩니다. 기타 음수 값은 불법입니다. 이 값은 일반적으로이 터미널에서 해당 기능이 없음을 의미하는 을 의미합니다. 하드웨어가 하드웨어와 일치하지 않는 컴퓨터는 정수를 2 바이트로 읽어야하며 little-endian 값을 계산해야합니다.


  • 을 입력의 종류를 분석하는 동안 첫 번째 문제는 8 비트의 사이즈가 고정되므로이 정확히되도록 크기를 보장 않으므로 일반 이전 문자가 사용될 수 없다는 8 비트. 그래서 나는 'Fixed width integer types'을 찾고 있었지만 B/w int8_t 또는 uint8_t을 선택하는 dillema에 직면했습니다. "구현이 직접 해당 유형을 지원하는 경우에만 제공됩니다". 그렇다면 유형을 충분히 이식 가능하도록 선택해야하는 이유는 무엇입니까?

  • 두 번째 문제는 Little Endian 형식의 16 바이트 데이터를 읽을 수있는 C++ 표준 라이브러리에 buffer.readInt16LE() 메서드가 없습니다. 그렇다면이 기능을 휴대용 & 안전한 방법으로 다시 구현하려면 어떻게해야합니까?

내가 이미 char 데이터 형식으로 읽기 시도했지만 확실히 내 컴퓨터에 쓰레기를 생성합니다. 적절한 입력은 infocmp 명령 (예 : $ infocmp xterm)으로 읽을 수 있습니다.


#include <fstream> 
#include <iostream> 
#include <vector> 

int main() 
{ 
    std::ifstream db(
     "/usr/share/terminfo/g/gnome", std::ios::binary | std::ios::ate); 

    std::vector<unsigned char> buffer; 

    if (db) { 
     auto size = db.tellg(); 
     buffer.resize(size); 
     db.seekg(0, std::ios::beg); 
     db.read(reinterpret_cast<char*>(&buffer.front()), size); 
    } 
    std::cout << "\n"; 
} 

$1 = std::vector of length 3069, capacity 3069 = {26 '\032', 1 '\001', 21 '\025', 
    0 '\000', 38 '&', 0 '\000', 16 '\020', 0 '\000', 157 '\235', 1 '\001', 
    193 '\301', 4 '\004', 103 'g', 110 'n', 111 'o', 109 'm', 101 'e', 124 '|', 
    71 'G', 78 'N', 79 'O', 77 'M', 69 'E', 32 ' ', 84 'T', 101 'e', 114 'r', 
    109 'm', 105 'i', 110 'n', 97 'a', 108 'l', 0 '\000', 0 '\000', 1 '\001', 
    0 '\000', 0 '\000', 1 '\001', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 
    0 '\000', 0 '\000', 0 '\000', 0 '\000', 1 '\001', 1 '\001', 0 '\000', 
.... 
.... 
+1

일부 코드는 내 친구에게 게시하십시오. 몇 바이트를 버퍼로 읽어 들이고 디버거로 살펴보십시오. –

+1

'char'는 모든 시스템에서 가장 작은 주소 지정 가능 유닛이되도록 보장됩니다 (그 때문에'sizeof (char)'가 항상 '1'로 지정됩니다). 따라서 8 비트 바이트를 갖는 시스템의 경우'char'는 8 비트가 보장됩니다. 그리고 지난 30 년 동안 만들어진 모든 시스템이 사실상 걱정할 필요가 없습니다. 프로그램을 1970 년대 이전의 시스템에 이식해야한다면 * 걱정할 필요가 있습니다. –

+1

'uint8_t' 또는'unsigned char'를 사용해야합니다. 'char' 타입은 컴파일러 설정에 따라'unsigned','signed' 또는'char' * 일 수 있습니다. –

답변

2

입력의 유형을 분석하는 동안 첫 번째 문제는 8 비트의 사이즈가 고정되므로하지 않으므로 일반 이전 문자가 사용될 수 없다는 정확하게 8 비트 크기를 보장합니다.

최소 8 비트 정수는 정상입니다.char은 정확히 8 비트는 아니지만 8 비트 이상이어야하므로 크기와 관련하여 어떤 경우에는 상위 비트가있는 경우 마스크해야 할 수도 있습니다 . 그러나 char은 서명되지 않을 수 있으며, 옥텟을 부호있는 값으로 해석하지 않으려면 대신 unsigned char을 사용하십시오.

두 번째 문제는 Little Endian 형식의 16 바이트 데이터를 읽을 수있는 C++ 표준 라이브러리의 buffer.readInt16LE() 메서드가 없다는 것입니다. 그렇다면이 기능을 휴대용 & 안전한 방법으로 다시 구현하려면 어떻게해야합니까?

한 번에 한 옥텟을 unsigned char으로 읽습니다. 첫 번째 옥텟을 변수에 할당합니다 (최소 16 비트를 나타낼만큼 충분히 큽니다). 두 번째 옥텟의 비트를 8만큼 왼쪽으로 시프트하고 복합을 비트 또는로 사용하여 변수에 지정합니다.

더 좋지만 아직 구현하지 않고 제 3 자의 기존 라이브러리를 사용하십시오.

이미 char 데이터 유형으로 읽으려고했으나 내 컴퓨터에 가비지가 생성되었습니다.

그런 다음 버그가있었습니다. 가비지 출력을 일으키는 char에는 문제가 없습니다. 이 문제를 해결하려면 디버거를 사용하는 것이 좋습니다.

+0

코드 및 샘플 출력을 추가했습니다. 잘못된 점을 알려주시겠습니까? –

+0

hmm 그래서 두 개의'unit8_t' 변수'x'와'y'를 정의하고,''db.read (reinterpret_cast (& x), sizeof (x)); '를 사용하여 데이터를 읽고 다른 곳에서 제안한 것을 했어요. 'unit16_t' -'result = x | (y << 8); 그리고 결과는'282'이었고 실제로는 8 진수에서'0432'입니다. 디버거 출력이 왜 그런지 확실하지 않습니다. 이 방법은 소형 및 대형 엔디안 시스템에서 모두 작동합니까? –

+0

네, 네이티브 엔디안이 무엇인지에 관계없이 리틀 엔디안을 네이티브 엔디안으로 변환합니다. – user2079303

관련 문제