2014-07-05 8 views
0

핸들로 사용되는 64 비트 정수가 있습니다. 이 64bit는 다음 필드로 분리해야 개별적으로 액세스 할 수 있도록이를 달성하기 위해 내가 생각할 수있는64 비트 정수 핸들 유형에 대한 간결한 비트 조작

size   : 30 bits 
offset   : 30 bits 
invalid flag : 1 bit 
immutable flag : 1 bit 
type flag  : 1 bit 
mapped flag : 1 bit 

두 가지 것이 있습니다 :

1) 전통적인 비트 연산 (& | << >>) 등 그러나 나는 이것을 약간은 이상하게 생각한다.

2)를 사용하여 비트 필드 구조체 :

handle.invalid = 1; 

하지만 비트 필드는 상당히 문제가 아닌 이식 이해 :

#pragma pack(push, 1) 
struct Handle { 
    uint32_t size  : 30; 
    uint32_t offset : 30; 
    uint8_t invalid : 1; 
    uint8_t immutable : 1; 
    uint8_t type  : 1; 
    uint8_t mapped : 1; 
}; 
#pragma pack(pop) 

그런 다음 필드에 접근이 매우 분명해진다.

코드 명확성과 가독성을 극대화하는 목적으로이 비트 조작을 구현하는 방법을 찾고 있습니다. 어떤 접근 방식을 취해야합니까?

사이드 노트 :

  • 핸들 크기가 64bit를 초과 할 수 없습니다;

  • 각 필드 크기가 존중되는 한 이러한 필드가 메모리에 배치되는 순서는 관계가 없습니다.

  • 핸들이 파일에 저장 /로드되지 않으므로 엔디안에 대해 걱정할 필요가 없습니다.

+1

비트 필드가 '문제가있는'것이 아니며 이식성을 예를 들어, 모든 필드를 0으로 지우거나 동시에 두 필드를 설정하거나 지우는 것과 같이 직접 작성할 수있는 매듭의 속도로 코드를 생성합니다. 심각한 코드 공간 제약 조건이 아니라면 어떤 코드를 작성하고 싶은지를 결정해야합니다. – EJP

+2

귀하의 요구 사항을 감안할 때, 비트 필드는 가장 간단한 솔루션처럼 보입니다. 비 호환성은 다른 컴파일러가 어떻게 다른 순서로 정렬할지에 따라 다릅니다. 하지만 그것들 모두에 대해'uint64_t'를 사용해야합니다. –

+0

"핸들"유형의 포인트는 핸들을 저장하는 모든 코드에서 불투명하다는 것입니다. 핸들을 생성하는 코드 만이 내용을 해석합니다. 물론 이식성이 문제가되지 않는다는 것을 의미합니다. –

답변

3

나는 bitfields 솔루션으로 갈 것입니다.

비트 필드는 이진 형식으로 저장하고 나중에 다른 컴파일러를 사용하거나 더 일반적으로 다른 컴퓨터 아키텍처를 사용하여 비트 필드를 읽는 경우에만 "이식 가능하지 않음"입니다. 필드 순서가 표준에 의해 정의되지 않았기 때문입니다.

응용 프로그램 내에서 비트 필드를 사용하면 "이진 이식성"(파일에 Handle을 저장하고 다른 컴파일러 나 다른 프로세서에서 컴파일 한 코드를 사용하여 다른 시스템에서 읽는 경우)이 가능합니다. 유형), 그것은 잘 작동합니다.

분명히 몇 가지 확인을해야합니다. sizeof(Handle) == 8은 어딘가에서 수행해야합니다. 크기를 올바르게 확보하고 컴파일러가 두 개의 30 비트 값을 별도의 32 비트 단어로 저장하지 않기로 결정했습니다.

struct Handle { 
    uint64_t size  : 30; 
    uint64_t offset : 30; 
    uint64_t invalid : 1; 
    uint64_t immutable : 1; 
    uint64_t type  : 1; 
    uint64_t mapped : 1; 
}; 

이 몇 가지 규칙입니다 컴파일러해야하지 "분할 요소", 당신은 uint32_t와 같은 무언가를 정의하면, 거기 :로 여러 아키텍처에서의 성공 가능성을 향상시키기 위해, 나는 아마 유형을 정의하는 것 필드에 남은 비트가 2 비트 뿐이므로 전체 30 비트가 다음 32 비트 요소로 이동합니다. [아마 대부분의 컴파일러에서 작동하지만, 경우에 따라 전체에서 동일한 64 비트 유형을 사용하는 것이 더 좋습니다.]

+0

고맙습니다 @MatsPetersson, 데이터 형식이 잘못되었습니다. 필드 크기와 가장 근접한 형식을 사용하는 것이 적절하다고 생각했기 때문에 구조체를'#pragma'로 압축해야했습니다. 'uint64_t' 만 사용하면 포장 할 필요없이 struct size = 8을 유지합니다. 그리고 확실히, 나는 "compile time assert"를 사용하려고합니다. – glampert

2

나는 비트 연산을 권장한다. 물론 클래스 내에서 모든 작업을 숨겨야합니다. 설정/가져 오기 작업을 수행 할 멤버 함수를 제공하십시오. 수업 내에서 상수를 신중하게 사용하면 대부분의 운영이 공정하게 투명 해집니다. 예를 들면 다음과 같습니다.

bool Handle::isMutable() const { 
    return bits & MUTABLE; 
} 

void Handle::setMutable(bool f) { 
    if (f) 
     bits |= MUTABLE; 
    else 
     bits &= ~MUTABLE; 
} 
+0

이것은 나에게 가난한 조언으로 생각납니다. 명시된 제약 조건 내에서 이동 및 마스크를 직접 작성하는 코드를 작성하면 최상의 상태에서도 정확하게 제로 이점을 제공하는 것처럼 보입니다. –