Bit-field
명시적 크기(비트 단위)를 가진 클래스 데이터 멤버를 선언합니다. 인접한 비트 필드 멤버들은 개별 바이트를 공유하고 걸쳐 사용하도록 패킹될 수도 있고, 그렇지 않을 수도 있습니다.
비트 필드 선언은 다음과 같은 선언자를 사용하는 클래스 데이터 멤버 선언 입니다:
identifier
(선택 사항)
attr
(선택 사항)
:
size
|
(1) | ||||||||
identifier
(선택 사항)
attr
(선택 사항)
:
size
brace-or-equal-initializer
|
(2) | (C++20부터) | |||||||
비트 필드의 type 은 선언 구문 의 decl-specifier-seq 에 의해 도입됩니다.
| attr | - | (since C++11) 임의 개수의 attributes 시퀀스 |
| identifier | - | 선언되는 비트 필드의 이름. 이름은 선택사항: 이름 없는 비트 필드는 지정된 수의 padding bits 를 도입합니다. |
| size | - | 0보다 크거나 같은 값을 가지는 integral constant expression . 0보다 클 경우, 이 비트 필드가 차지할 비트 수입니다. 값 0은 이름 없는 비트 필드에서만 허용되며 특별한 의미 를 가집니다. |
| brace-or-equal-initializer | - | 이 비트 필드와 함께 사용할 default member initializer |
목차 |
설명
비트 필드의 타입은 오직 정수형( bool 포함) 또는 (cv 한정자가 있을 수 있는) 열거형만 가능하며, 이름 없는 비트 필드는 cv 한정된 타입으로 선언될 수 없습니다.
비트 필드는 static data member 가 될 수 없습니다.
비트 필드 prvalue 는 존재하지 않습니다: lvalue-to-rvalue 변환은 항상 비트 필드의 기반 타입 객체를 생성합니다.
비트 필드의 비트 수는 해당 비트 필드가 저장할 수 있는 값의 범위를 제한합니다:
가능한 출력:
7 0
여러 개의 인접한 비트 필드는 일반적으로 함께 패킹됩니다(이 동작은 구현에 따라 정의됨):
#include <bit> #include <cstdint> #include <iostream> struct S { // 일반적으로 2바이트를 차지함: unsigned char b1 : 3; // 첫 번째 바이트의 처음 3비트는 b1 unsigned char : 2; // 첫 번째 바이트의 다음 2비트는 사용되지 않음 unsigned char b2 : 6; // b2를 위한 6비트 - 첫 번째 바이트에 맞지 않음 => 두 번째 바이트 시작 unsigned char b3 : 2; // b3를 위한 2비트 - 두 번째 바이트의 다음 (그리고 마지막) 비트들 }; int main() { std::cout << sizeof(S) << '\n'; // 일반적으로 2를 출력 S s; // 구별 가능한 필드 값 설정 s.b1 = 0b111; s.b2 = 0b101111; s.b3 = 0b11; // S 내 필드들의 레이아웃 표시 auto i = std::bit_cast<std::uint16_t>(s); // 일반적으로 1110000011110111을 출력 // 분석: └┬┘├┘└┬┘└─┬──┘└┤ // b1 u a b2 b3 // 여기서 "u"는 구조체에서 지정된 사용되지 않은 :2를 표시하고, // "a"는 다음 필드를 바이트 정렬하기 위해 컴파일러가 추가한 패딩을 표시함. // 바이트 정렬은 b2의 타입이 unsigned char로 선언되었기 때문에 발생함; // b2가 uint16_t로 선언되었다면 "a"가 없이 b2가 "u"에 인접했을 것임. for (auto b = i; b; b >>= 1) // LSB-첫 번째로 출력 std::cout << (b & 1); std::cout << '\n'; }
가능한 출력:
2 1110000011110111
크기가 0인 특수한 이름 없는 비트 필드는 패딩을 강제로 분리하는 데 사용할 수 있습니다. 이는 다음 비트 필드가 해당 할당 단위의 시작 부분에서 시작하도록 지정합니다:
#include <iostream> struct S { // will usually occupy 2 bytes: // 3 bits: value of b1 // 5 bits: unused // 2 bits: value of b2 // 6 bits: unused unsigned char b1 : 3; unsigned char :0; // start a new byte unsigned char b2 : 2; }; int main() { std::cout << sizeof(S) << '\n'; // usually prints 2 // would usually print 1 if not for // the padding break in line 11 }
가능한 출력:
2
지정된 비트 필드의 크기가 해당 유형의 크기보다 큰 경우, 값은 유형에 의해 제한됩니다:
std::
uint8_t
b
:
1000
;
는 여전히
[
0
,
255
]
범위의 값을 보유합니다. 추가 비트는
패딩 비트
입니다.
비트 필드는 바이트의 시작 부분에서 반드시 시작하지 않기 때문에, 비트 필드의 주소를 취할 수 없습니다. 비트 필드에 대한 포인터와 비-const 참조는 불가능합니다. const 참조를 초기화 할 때 비트 필드에서 초기화하는 경우, 임시 객체가 생성되고(그 타입은 비트 필드의 타입임) 비트 필드의 값으로 복사 초기화된 후, 참조가 해당 임시 객체에 바인딩됩니다.
|
비트 필드에 대한 기본 멤버 초기화자 가 없습니다: int b : 1 = 0 ; 와 int b : 1 { 0 } 는 잘못된 형식입니다. |
(C++20 이전) |
|
비트 필드의 크기와 기본 멤버 초기화자 사이에 모호성이 있는 경우, 유효한 크기를 형성하는 가장 긴 토큰 시퀀스가 선택됩니다: int a; const int b = 0; struct S { // 단순한 경우 int x1 : 8 = 42; // OK; "= 42"는 brace-or-equal-initializer int x2 : 8 {42}; // OK; "{42}"는 brace-or-equal-initializer // 모호성 int y1 : true ? 8 : a = 42; // OK; brace-or-equal-initializer가 없음 int y2 : true ? 8 : b = 42; // error: const int에 할당할 수 없음 int y3 : (true ? 8 : b) = 42; // OK; "= 42"는 brace-or-equal-initializer int z : 1 || new int{0}; // OK; brace-or-equal-initializer가 없음 }; |
(C++20 이후) |
참고 사항
비트 필드의 다음 속성들은 구현 시 정의됨 입니다:
- 부호 있는 비트 필드에 범위를 벗어난 값을 할당하거나 초기화할 때 발생하는 값, 또는 부호 있는 비트 필드를 범위를 넘어 증가시킬 때 발생하는 값.
- 클래스 객체 내에서 비트 필드의 실제 할당 세부 사항에 관한 모든 것.
-
- 예를 들어, 일부 플랫폼에서는 비트 필드가 바이트를 걸쳐 있지 않지만 다른 플랫폼에서는 그렇지 않습니다.
- 또한 일부 플랫폼에서는 비트 필드가 왼쪽에서 오른쪽으로 패킹되지만 다른 플랫폼에서는 오른쪽에서 왼쪽으로 패킹됩니다.
C 프로그래밍 언어에서, 비트 필드의 너비는 기본 타입의 너비를 초과할 수 없으며, 명시적으로
int
비트 필드가
signed
또는
unsigned
로 지정되지 않았을 때 부호 있는지 없는지는 구현에 따라 정의됩니다. 예를 들어,
int
b
:
3
;
는 C에서 값의 범위가
[
0
,
7
]
또는
[
-
4
,
3
]
일 수 있지만, C++에서는 후자의 선택만 허용됩니다.
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 324 | C++98 |
비트 필드에 대한 할당의 반환 값이
비트 필드인지 여부가 명시되지 않음 |
lvalue를 반환할 수 있는 연산자에 대한
비트 필드 명세 추가 |
| CWG 739 | C++98 |
signed
도
unsigned
도 선언되지 않은 비트 필드의 부호가
구현에 따라 정의됨 |
기본 타입과 일관되게 지정 |
| CWG 2229 | C++98 | 이름 없는 비트 필드를 cv-qualified 타입으로 선언할 수 있었음 | 금지됨 |
| CWG 2511 | C++98 | 비트 필드 타입에서 cv-qualification이 허용되지 않았음 |
비트 필드가 cv-qualified
열거형 타입을 가질 수 있음 |
참고문헌
- C++23 표준 (ISO/IEC 14882:2024):
-
- 11.4.10 비트 필드 [class.bit]
- C++20 표준(ISO/IEC 14882:2020):
-
- 11.4.9 비트 필드 [class.bit]
- C++17 표준 (ISO/IEC 14882:2017):
-
- 12.2.4 비트 필드 [class.bit]
- C++14 표준(ISO/IEC 14882:2014):
-
- 9.6 비트 필드 [class.bit]
- C++11 표준(ISO/IEC 14882:2011):
-
- 9.6 비트 필드 [class.bit]
- C++03 표준(ISO/IEC 14882:2003):
-
- 9.6 비트 필드 [class.bit]
- C++98 표준(ISO/IEC 14882:1998):
-
- 9.6 비트 필드 [class.bit]
참고 항목
|
고정 길이 비트 배열 구현
(클래스 템플릿) |
|
|
공간 효율적인 동적 비트셋
(클래스 템플릿 특수화) |
|
| Bit manipulation (C++20) | 개별 비트 및 비트 시퀀스에 접근, 조작, 처리하기 위한 유틸리티 |
|
C documentation
for
Bit-fields
|
|