2017-10-02 1 views
1

저는 C와 함께 작업 중이며 32 비트 부호없는 정수에서 비트 세트를 변경하는 방법을 알아 내려고하고 있습니다. 내가 진에서부호없는 int에서 바이트 그룹을 수동으로 변경

int a = 17212403u; 

이있는 경우 예를 들어

는 그 1000001101010001111110011된다. 자, 내가이 비트들을 리틀 엔디안 포맷으로 배열했다고 가정하면, 최대한 오른쪽 비트가 1을 나타내는 것과 2 번째가 오른쪽을 2 등인 것처럼 어떻게 비트 그룹을 수동으로 변경할 수 있습니까?

예를 들어, 11 번째 비트에서 15 번째 비트에 십진수 17이되도록 비트를 변경하려고한다고 가정합니다. 어떻게 가능합니까?

unsigned int range = (a << (sizeof(a) * 8) - 14) >> (28) 

을하지만 어디에서에 갈 확실하지 않다 :

나는 같은 수행하여 그 범위를 점점 생각했다.

+1

'int a = 17212403u;'는 _unsigned_ 값을 _signed_ 변수에 할당합니다. 시프트를 확실히 수행하는 것은 부호없는 변수 및 상수를 고수하는 것이 훨씬 덜 문제입니다. 'unsigned a = 17212403u; – chux

+1

17이 10001B라고 생각하십시오. 비트 11-15도 5 비트이므로 적합 할 것입니다. 먼저, NOT (11111B << 11)의 마스크와 AND 연산을하여이 비트들을 강제로 낮추십시오. 그런 다음 17 개를 11 개 위로 이동하고 또는에 넣습니다. –

+4

비트 "주문"에는 리틀 및 빅 엔디안이 적용되지 않습니다. 비트는 개별적으로 주소 지정이 가능하지 않으므로 더 낮은 주소에 호소 할 개념이 없습니다. 그러나 little-endian * byte * 정렬은 "가장 왼쪽"바이트 (가장 낮은 주소를 가진 바이트)가 저 순서 끝에 있다는 것을 의미합니다. "리틀 엔디안"이 의미하는 것과는 반대입니다 . – rici

답변

2

(1) 먼저 비트 11..15와 (2)를 지우고 설정하려는 값에 따라 비트를 설정해야합니다. (1)을 달성하려면, 지우고 자하는 비트를 제외하고 모든 비트가 1으로 설정된 "마스크"를 작성하십시오. a & bitMask을 사용하여 비트를 0으로 설정하십시오. 그런 다음 | myValue을 사용하여 비트를 원하는 값으로 설정하십시오. 올바른 위치에 마스크와 가치를 부여하기 위해 비트 시프트 연산자 <<를 사용 :

int main(int argc, char** argv) { 

    // Let's assume a range of 5 bits 
    unsigned int bitRange = 0x1Fu; // is ...00000000011111 

    // Let's assume to position the range from bit 11 onwards (i.e. move 10 left): 
    bitRange = bitRange << 10;    // something like 000000111110000000000 
    unsigned int bitMask = ~bitRange;  // something like 111111000001111111111 
    unsigned int valueToSet = (17u << 10); // corresponds to 000000101110000000000 

    unsigned int a = (17212403u & bitMask) | valueToSet; 

    return 0; 
} 

이 무슨 일인지 설명하는 긴 버전입니다. 간단히 말해 다음과 같이 쓸 수도 있습니다.

unsigned int a = (17212403u & ~(0x1Fu << 10)) | (17u << 10) 
2

11 번째 비트 ~ 15 번째 비트는 15 비트를 포함한다고 가정 할 때 5 비트입니다. , 0x1f << 11

이제 우리는 우리가 원래 변수에 지우려면 11 ~ 15 비트의 마스크를 가지고 :

0x1f이 그럼 당신은 (11)의 위치 왼쪽이 5 개 비트를 이동 : 5 비트는 16 진수 값입니다 어느 - 우리가 그 반전 마스크는 마스크, 비트 가변 반전 기준 : a & ~(0x1f << 11)

다음 11 비트의 최대 값 (17)을 이동한다 : 5 비트로이어서 17 << 11

우리는 비트 단위 또는 우리는 다음을 정리했다 :

unsigned int b = (a & ~(0x1f << 11)) | (17 << 11) 
+2

'0x1fu, 17u'와 같은 부호없는 상수를 사용하는 것이 좋습니다. – chux

0

비트 필드 사용을 고려하십시오. 이렇게하면 구조체의 정수 멤버 인 것처럼 정수의 하위 섹션에 이름을 지정하고 액세스 할 수 있습니다. C의 비트 필드에 대한 정보를 들어

볼 : 다음은 비트 필드를 사용하여, 당신이 원하는 것을 할 수있는 코드가 https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm

입니다. 구조체의 "middle5"멤버는 비트 11-15를 보유합니다. "lower11"멤버는 하위 11 비트의 필러이므로 "middle5"멤버가 올바른 위치에있게됩니다.프로그램의

#include <stdio.h> 

void showBits(unsigned int w) 
{ 
    unsigned int bit = 1<<31; 
    while (bit > 0) 
    { 
    printf("%d", ((bit & w) != 0)? 1 : 0); 
    bit >>= 1; 
    } 
    printf("\n"); 
} 

int main(int argc, char* argv[]) 
{ 
    struct aBitfield { 
     unsigned int lower11: 11; 
     unsigned int middle5: 5; 
     unsigned int upper16: 16; 
    }; 

    union uintBits { 
    unsigned int  whole; 
    struct aBitfield parts; 
    }; 

    union uintBits b; 

    b.whole = 17212403u; 

    printf("Before:\n"); 
    showBits(b.whole); 

    b.parts.middle5 = 17; 

    printf("After:\n"); 
    showBits(b.whole);  
} 

출력 :

물론
Before: 
00000001000001101010001111110011 
After: 
00000001000001101000101111110011 

, 당신은 다양한 분야에 대한보다 의미있는 이름을 사용하고자하는 것입니다.

비트 필드는 다른 플랫폼에서 다르게 구현 될 수 있으므로 완전히 이식 가능하지 않을 수 있습니다.

관련 문제