2014-04-05 3 views
-1

함수는 vector<unsigned char> byteVector(long long UID)이고, UID (64 비트 정수)의 바이트 표현은 vector으로 반환됩니다. 이 벡터는 나중에이 데이터를 파일에 쓰는 데 사용됩니다.64 비트 정수를 7 비트 문자의 배열로 변환하십시오.

이제 파이썬으로 파일을 읽고 싶다고 결정했기 때문에 utf-8 표준을 준수해야합니다. 즉, only use the first 7bits of each char을 사용할 수 있습니다. 최상위 비트가 1이면 더 이상 ASCII 문자를 지원하기 때문에 더 이상 문자열로 디코딩 할 수 없습니다. 또한 ASCII 문자열을 지원하는 커맨드 라인 인터페이스 (Command Line Interface)를 통해이 문자열들을 다른 프로세스로 전달해야 할 것입니다.

그 문제가 발생하기 전에 8 별도의 바이트로 64 비트 정수를 분할에 대한 나의 접근 방식은 정말 좋은 일 다음은이었다 "

물론
vector<unsigned char> outputVector = vector<unsigned char>(); 
unsigned char * uidBytes = (unsigned char*) &UID_; 
for (int i = 0; i < 8; i++){ 
    outputVector.push_back(uidBytes[i]); 
} 

구속으로, 더 이상 작동하지 않습니다 HBit 1하지 않을 수 있습니다 "물론이 함께 한 push_back 호출을 대체하는 것입니다 이제 각 unsigned char 127 내 가장 쉬운 옵션의 최대 값을 제한 :

outputVector.push_back(uidBytes[i]/128); 
outputVector.push_back(uidBytes[i] % 128); 

을하지만이 종류의 O를 보인다 f 낭비, 각각의 첫 번째로 unsigned char 쌍 수 밖에 0 또는 1 및 나는 낭비하는 일부 공간 (6 바이트) 그렇지 않으면 사용할 수 있습니다.

64 비트를 저장해야하고 바이트 당 7 비트를 사용할 수 있으므로 64 // 7 + 64 % 7 = 10 바이트가 필요합니다.

실제로는 (내가 작성한 파일 중 1KB에 도달 한 파일이 없습니다.)하지만 이전에 8 바이트를 사용하고 있었고 이제 10을 사용할 때 약간의 낭비가 될 것입니다 (9, 미안) 충분할 것입니다. 따라서 :

어떻게 64 비트 정수를 10 비트 7 비트 정수로 변환합니까?

이것은 아마도 너무 많은 최적화이지만이 문제 (아마도 시프트 연산자 사용)에 대한 아주 멋진 해결책이 될 수 있습니다. 그리고 나는 그것을보기에 정말로 관심이 있습니다.

+1

base64는 11 바이트를 제공해야하며이를 구현하는 기존 라이브러리가 있어야합니다. 또한이 도구로 작업 할 수있는 도구가 많이 있습니다. –

+0

나는 당신이 원하는 것을 얻지 못한다. 7 비트 튜플을 원하지만 바이트의 8 번째 비트를 기다리지 않습니까? 일반적으로 7 비트 변수는 없습니다. 만약 당신이 (이론적으로) 정의되지 않은 동작을 가진다면, 유니온과 비트 필드 구조체의 조합을 사용하십시오. – deviantfan

+0

@deviantfan 문제는 UTF-8 코드 텍스트가 7 비트 (문자의 바이트 값이 127 이상이되지 않음)이기 때문에 8 번째 비트를 낭비하지 않기 때문에 각 바이트의 8 번째 비트를 낭비해야한다는 것입니다. 왜 그런지 묻지 말고 표준을 준수해야합니다. 설명을 위해 질문을 수정하겠습니다. – iFreilicht

답변

4

비트 시프트를 사용하여 7 비트 조각의 64 비트 정수를 사용할 수 있습니다. 그러나 10 비트의 7 비트 정수가 필요합니다. 9 비트는 충분하지 않습니다. 9 * 7 = 63, 1 비트가 부족합니다.

std::uint64_t uid = 42; // Your 64-bit input here. 
    std::vector<std::uint8_t> outputVector; 

    for (int i = 0; i < 10; i++) 
    { 
    outputVector.push_back(uid >> (i * 7) & 0x7f); 
    } 

모든 반복에서 입력 비트를 7의 배수로 시프트하고 7 비트 부분을 마스크 아웃합니다. 8 비트 숫자의 최상위 비트는 0입니다. 벡터의 숫자는 "반전 됨"입니다. 최하위 비트는 가장 낮은 인덱스를 갖습니다. 그러나 올바른 방법으로 부품을 디코딩하는 경우에는 관계가 없습니다. 순서는 여전히 제어 문자를 포함하고 및 \0 수 있습니다

std::uint64_t decoded = 0; 
for (int i = 0; i < 10; i++) 
{ 
    decoded |= static_cast<std::uint64_t>(outputVector[i]) << (i * 7); 
} 

UTF-8로 인코딩 된 텍스트로 결과 벡터를 해석하는 나쁜 생각처럼 보인다 참고 : 다음과 같이 디코딩을 수행 할 수 있습니다. 인쇄 가능한 문자로 64 비트 정수를 인코딩하려면 base64을보십시오. 이 경우 64 비트를 인코딩하려면 문자가 하나 더 필요합니다 (총 11 개).

+0

내 질문에 이미 바이트 수를 편집했습니다. 대답 주셔서 감사합니다, 그것은 제가 찾고 있던 것입니다! 설명을 위해 : 숫자가 뒤집어 진다고 말하면 "바이트"가 역순으로 쓰여지는 것을 말하는 것입니까? 또한 iteration을 되 돌리는 것으로 해결할 수 없었습니까? – iFreilicht

+0

무슨 뜻입니까, 왼쪽에서 오른쪽으로 벡터를 인쇄 할 때, 최하위 비트는 왼쪽 바이트에 있고 최상위 비트는 오른쪽 바이트에 있습니다. 필기체 시스템에서 가장 중요한 자릿수는 보통 왼쪽에 있으므로이 의미에서 바이트는 "뒤집어"있습니다. 그리고 가장 중요한 인덱스를 가장 낮은 인덱스에서 사용하는 것을 선호한다면 단순히 뒤로 이동할 수 있습니다. – Ruud

1

어셈블리 언어를 사용하는 것이 좋습니다.

많은 어셈블리 언어는 비트를 "예비"캐리 비트로 이동하고 캐리 비트를 레지스터로 시프트하는 명령어가 있습니다. C 언어에는이 작업을 수행하기위한 편리하고 효율적인 방법이 없습니다.

알고리즘 :

for i = 0; i < 7; ++i 
{ 
    right shift 64-bit word into carry. 
    right shift carry into character. 
} 

또한 std::bitset를 사용하여 조사한다.

+0

일반적인 비트 연산자를 사용하는 것보다 어셈블리를 더 좋게 만드는 이유는 무엇입니까? – iFreilicht

+1

코드를 작성하고 어셈블리 목록을보십시오. 어셈블리의 경우 비트 시프트는 두 가지 지침입니다. 컴파일러는 얼마나 많은 명령어를 생성합니까? –

관련 문제