C Language
비트 필드
수색…
소개
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 경계에서 시작하게하므로 c2
와 c3
사이에 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;
}
결론적으로, 비트 필드는 한정된 범위를 가질 수있는 변수가 많은 메모리 제약 상황에서 일반적으로 사용됩니다.
비트 필드 사용 금지
- 비트 필드의 배열, 비트 필드에 대한 포인터 및 비트 필드를 반환하는 함수는 허용되지 않습니다.
- 주소 연산자 (&)는 비트 필드 멤버에 적용 할 수 없습니다.
- 비트 필드의 데이터 유형은 필드의 크기를 포함 할만큼 충분히 넓어야합니다.
-
sizeof()
연산자는 비트 필드에 적용 할 수 없습니다. - 비트 필드를위한
typedef
를typedef
으로 생성하는 방법은 없습니다 (물론 비트 필드를 포함하는 구조체의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 */
}