수색…


소개

C의 대부분의 변수는 정수 바이트 수의 크기를가집니다. 비트 필드는 필수적으로 정수 바이트를 차지하지 않는 구조의 일부입니다. 그들은 모든 비트 수 있습니다. 다중 비트 필드는 단일 저장 장치로 패킹 될 수 있습니다. 그것들은 표준 C의 일부이지만 구현 정의 된 많은 측면들이 있습니다. 그들은 C에서 가장 휴대하기 어려운 부분 중 하나입니다.

통사론

  • 타입 지정자 식별자 : size;

매개 변수

매개 변수 기술
형식 지정자 signed unsigned , unsigned , int 또는 _Bool
식별자 구조체의이 필드 이름
크기 이 필드에 사용할 비트 수

비고

비트 필드에 대한 유일한 휴대용 유형이있다 signed , unsigned 또는 _Bool . 일반 int 비트 필드, 그것을 구현 정의 지정자 여부 ... 유형은 사용할 수 있지만 표준 (§6.7.2¶5)를 말한다 int 동일한 유형 지정 signed int 또는 같은 종류의 unsigned int .

다른 정수 유형은 특정 구현에서 허용 될 수 있지만이를 사용하는 것은 이식 가능하지 않습니다.

비트 필드

간단한 비트 필드는 관련된 특정 비트 수가있을 수있는 것을 설명하는 데 사용될 수 있습니다.

struct encoderPosition {
   unsigned int encoderCounts : 23;
   unsigned int encoderTurns  : 4;
   unsigned int _reserved     : 5;
};

이 예제에서 우리는 23 비트의 단 정밀도와 4 비트를 가진 엔코더가 다중 턴을 설명한다고 생각합니다. 비트 필드는 특정 비트 수와 관련된 데이터를 출력하는 하드웨어와 인터페이싱 할 때 자주 사용됩니다. 또 다른 예로는 FPGA와의 통신이 있습니다. FPGA는 32 비트 섹션의 메모리에 데이터를 쓰고 하드웨어 판독을 허용합니다.

struct FPGAInfo {
    union {
        struct bits {
            unsigned int bulb1On  : 1;
            unsigned int bulb2On  : 1;
            unsigned int bulb1Off : 1;
            unsigned int bulb2Off : 1;
            unsigned int jetOn    : 1;
        };
        unsigned int data;
   };
};

이 예제에서는 개별 비트의 데이터에 액세스하거나 전체적으로 데이터 패킷을 쓰는 데 일반적으로 사용되는 구조를 보여 줬습니다 (FPGA의 기능을 에뮬레이션). 다음과 같이 비트에 액세스 할 수 있습니다.

FPGAInfo fInfo;
fInfo.data = 0xFF34F;
if (fInfo.bits.bulb1On) {
    printf("Bulb 1 is on\n");
}

이것은 유효하지만 C99 표준 6.7.2.1, 항목 10 :

단위 내의 비트 필드 할당 순서 (상위에서 하위 또는 하위에서 상위)는 구현에 따라 정의됩니다.

이런 식으로 비트 필드를 정의 할 때 엔디안을 알아야합니다. 따라서 컴퓨터의 엔디안을 확인하기 위해 전 처리기 지시문을 사용해야 할 수도 있습니다. 예를 들면 다음과 같습니다.

typedef union {
    struct bits {
#if defined(WIN32) || defined(LITTLE_ENDIAN)
    uint8_t commFailure :1;
    uint8_t hardwareFailure :1;
    uint8_t _reserved :6;
#else
    uint8_t _reserved :6;
    uint8_t hardwareFailure :1;
    uint8_t commFailure :1;
#endif
    };
    uint8_t data;
} hardwareStatus;

비트 필드를 작은 정수로 사용하기

#include <stdio.h>

int main(void)
{
    /* define a small bit-field that can hold values from 0 .. 7 */
    struct
    {
        unsigned int uint3: 3;
    } small;

    /* extract the right 3 bits from a value */
    unsigned int value = 255 - 2; /* Binary 11111101 */
    small.uint3 = value;          /* Binary      101 */
    printf("%d", small.uint3);

    /* This is in effect an infinite loop */
    for (small.uint3 = 0; small.uint3 < 8; small.uint3++)
    {
        printf("%d\n", small.uint3);
    }

    return 0;
}

비트 필드 정렬

비트 필드는 문자 너비보다 작은 구조 필드를 선언하는 기능을 제공합니다. 비트 필드는 바이트 레벨 또는 워드 레벨 마스크로 구현됩니다. 다음 예제에서는 8 바이트 구조를 사용합니다.

struct C
{
    short s;            /* 2 bytes */
    char  c;            /* 1 byte */
    int   bit1 : 1;     /* 1 bit */
    int   nib  : 4;     /* 4 bits padded up to boundary of 8 bits. Thus 3 bits are padded */
    int   sept : 7;     /* 7 Bits septet, padded up to boundary of 32 bits. */
};

이 주석은 하나의 가능한 레이아웃을 설명하지만 표준 에서 주소 지정이 가능한 저장 장치의 정렬이 지정되지 않았기 때문에 다른 레이아웃도 가능합니다.

명명되지 않은 비트 필드의 크기는 제한되지 않지만 초기화되거나 참조 될 수는 없습니다.

제로 폭 비트 필드는 이름을 부여 할 수 없으며 다음 필드를 비트 필드의 데이터 유형에 의해 정의 된 경계에 맞 춥니 다. 이것은 비트 필드들 사이의 비트들을 패딩함으로써 달성된다.

구조 'A'의 크기는 1 바이트입니다.

struct A
{
    unsigned char c1 : 3;
    unsigned char c2 : 4;
    unsigned char c3 : 1;
};

구조 B에서 첫 번째 명명되지 않은 비트 필드는 2 비트를 건너 뜁니다. c2 이후의 제로 너비 비트 필드는 c3 을 char 경계에서 시작하게하므로 c2c3 사이에 3 비트를 건너 뜁니다 c4 뒤에 3 개의 패딩 비트가 있으므로 구조의 크기는 2 바이트입니다.

struct B
{
    unsigned char c1 : 1;
    unsigned char    : 2;    /* Skips 2 bits in the layout */
    unsigned char c2 : 2;
    unsigned char    : 0;    /* Causes padding up to next container boundary */ 
    unsigned char c3 : 4;
    unsigned char c4 : 1;
};

비트 필드는 언제 유용합니까?

비트 필드는 많은 변수를 구조와 유사한 하나의 객체로 묶는 데 사용됩니다. 따라서 메모리 사용이 줄어들고 특히 임베디드 환경에서 유용합니다.

 e.g. consider the following variables having the ranges as given below.
 a --> range 0 - 3
 b --> range 0 - 1
 c --> range 0 - 7
 d --> range 0 - 1
 e --> range 0 - 1

이러한 변수를 개별적으로 선언하면 각 변수는 적어도 8 비트 정수 여야하며 필요한 총 공간은 5 바이트가됩니다. 또한 변수는 8 비트 부호없는 정수 (0-255)의 전체 범위를 사용하지 않습니다. 여기서 우리는 비트 필드를 사용할 수 있습니다.

typedef struct {
   unsigned int a:2;
   unsigned int b:1;
   unsigned int c:3;
   unsigned int d:1;
   unsigned int e:1;
} bit_a;

구조의 비트 필드는 다른 구조와 동일하게 액세스됩니다. 프로그래머는 변수가 범위로 ​​작성되었는지주의해야합니다. 범위를 벗어나면 동작이 정의되지 않습니다.

int main(void)
{
   bit_a bita_var;
   bita_var.a = 2;              // to write into element a
   printf ("%d",bita_var.a);    // to read from element a.
   return 0;
}

종종 프로그래머는 비트 필드 집합을 0으로 만들고 싶어합니다. 이것은 요소별로 수행 할 수 있지만 두 번째 방법이 있습니다. 구조의 크기보다 크거나 같은 부호없는 유형으로 위 구조의 공용체를 작성하기 만하면됩니다. 그 다음, 비트 필드들의 전체 세트는이 부호없는 정수를 제로로함으로써 제로화 될 수있다.

typedef union {
    struct {
       unsigned int a:2;
       unsigned int b:1;
       unsigned int c:3;
       unsigned int d:1;
       unsigned int e:1;
    };
    uint8_t data;
} union_bit;    

사용법은 다음과 같습니다.

int main(void)
{
   union_bit un_bit;
   un_bit.data = 0x00;        // clear the whole bit-field
   un_bit.a = 2;              // write into element a
   printf ("%d",un_bit.a);    // read from element a.
   return 0;
}

결론적으로, 비트 필드는 한정된 범위를 가질 수있는 변수가 많은 메모리 제약 상황에서 일반적으로 사용됩니다.

비트 필드 사용 금지

  1. 비트 필드의 배열, 비트 필드에 대한 포인터 및 비트 필드를 반환하는 함수는 허용되지 않습니다.
  2. 주소 연산자 (&)는 비트 필드 멤버에 적용 할 수 없습니다.
  3. 비트 필드의 데이터 유형은 필드의 크기를 포함 할만큼 충분히 넓어야합니다.
  4. sizeof() 연산자는 비트 필드에 적용 할 수 없습니다.
  5. 비트 필드를위한 typedeftypedef 으로 생성하는 방법은 없습니다 (물론 비트 필드를 포함하는 구조체의 typedef 를 만들 수는 있습니다).
typedef struct mybitfield
{
    unsigned char c1 : 20;   /* incorrect, see point 3 */
    unsigned char c2 : 4;    /* correct */
    unsigned char c3 : 1;
    unsigned int x[10]: 5;   /* incorrect, see point 1 */
} A;

int SomeFunction(void)
{
    // Somewhere in the code
    A a = { … };
    printf("Address of a.c2 is %p\n", &a.c2);      /* incorrect, see point 2 */
    printf("Size of a.c2 is %zu\n", sizeof(a.c2)); /* incorrect, see point 4 */
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow