27. 구조체(struct) - 비트 필드(bit field)
구조체의 기능 중에서 많이 사용하지 않지만, 정수형 데이터를 비트 단위로 나누어서 사용할 수 있는 기능을 제공합니다. 이를 구조체의 bit field라고 합니다. struct 구조체명 { 정수형 멤버명1 :
www.it-note.kr
위 블로그 글을 정리하고 정리한 내용입니다.
union( 공용체 ) 관련 내용을 찾아보면서 struct 멤버 변수에 나와있는 ' : ' ( 비트 필드) 에 대해 공부했다.
비트 필드란 우선 메모리를 보다 아끼기 위해 생긴것이다.
멤버변수들의 표현이 4byte 로 충분하다면 4byte 안에서 지들끼리 나눠서 사용하겠다는 목적으로 생긴것이다.
구조체의 기능 중에서 많이 사용하지 않지만, 정수형 데이터를 비트 단위로 나누어서 사용할 수 있는 기능을 제공합니다. 이를 구조체의 bit field라고 합니다.
struct 구조체명
{
정수형 멤버명1 : 비트수;
정수형 멤버명2 : 비트수;
...
};
위의 정수형은 char, unsigned char, short, unsigned char, int, unsigned int, long, unsigned long형이 올 수 있습니다.
예). 파일 접근 권한
struct file_access
{
unsigned short other : 3; // rwx
unsigned short group : 3; // rwx
unsigned short owner : 3; // rwx
unsigned short type : 3;
unsigned short egroup : 1;
unsigned short euser : 1;
};
위의 bit field 구조체는 총 14bit의 데이터를 관리할 수 있는 형태가 된다. 이 경우 구조체의 크기는 unsigned short 타입으로 2바이트 크기를 갖게 된다.
예). 다른 타입이 섞여 있는 경우
struct option
{
unsigned char flag1 : 1;
unsigned short flag2 : 1;
};
위와 같이 field의 데이터 타입을 다르게 표현하여도 상관이 없으나, 구조체의 크기는 가장 큰 타입의 크기를 따르므로 2바이트를 갖게 됩니다. (X) -> 4 바이트 를 갖는다. (이게 맞다.)
예). member의 bit의 합이 데이터 타입보타 큰 경우
struct option
{
unsigned char opt1 : 3;
unsigned char opt2 : 6;
};
위의 같이 field의 데이터 타입이 8bit로 1바이트인데, 전체 bit수가 8보다 크게 되면, 오류가 발생하는 것이 아니라 그 데이터 타입의 크기만큼 증가하여 2바이트를 차지하게 됩니다.
그렇다면 아래의 구조체 크기는 어떻게 될까?
아래 MSDN 을 참고하면 더 자세히 알 수 있다.
https://docs.microsoft.com/ko-kr/cpp/cpp/cpp-bit-fields?view=msvc-170
C++ 비트 필드
자세한 정보: C++ 비트 필드
docs.microsoft.com
Bit Field의 응용
만약, IPv4의 주소를 저장하는 것을 표현한다면
#include <string.h>
struct IPv4_Addr
{
unsigned int addr4 : 8;
unsigned int addr3 : 8;
unsigned int addr2 : 8;
unsigned int addr1 : 8;
};
int main()
{
unsigned int ipaddr;
struct IPv4_Addr addr;
// ip 127.0.0.1
addr.addr1 = 127;
addr.addr2 = 0;
addr.addr3 = 0;
addr.addr4 = 1;
memcpy(&ipaddr, &addr, sizeof(unsigned int));
}
형식으로 표현할 수 있으며, addr1 ~ addr4까지는 각각 8bit씩 차지하므로 전체 크기는 4바이트를 차지하는 구조체가 됩니다. 먼저 선언한 변수가 하위 bit 부분이 됩니다. 그리고 이것을 unsigned int 변수에 복사를 하면 bit 연산자로 하지 않고 쉽게 처리할 수 있습니다.
조합형 한글을 표현하는 방식으로 이 bit field 를 사용 할 수 도 있다.
typedef struct
{
unsigned short end : 5; // 종성
unsigned short mid : 5; // 중성
unsigned short first : 5; // 초성
unsigned short han_yn : 1; // 한글비트 1이면 한글, 그렇지 않으면 한글 아님
};
이를 통하여 한글의 제자원리를 완벽하게 지원하는 형태였는 데, 요즘은 모두 완성형의 형태로 사용하고 있다.
또한, 공용체(union)과 더불어 CPU의 register 메모리 AH, AL, AX 등의 표현을 쉽게 설정하고 이 값들을 BIOS 인터럽트 번호로 전달하여 하드웨어 제어를 하는 초창기의 PC에서 많이 사용되었습니다. (16bit 컴퓨터 시절...)
union AX
{
unsigned short ax; // AX register의 전체 크기
struct {
unsigned short al : 8; // register의 하위 바이트
unsigned short ah : 8; // register의 상위 바이트
};
};
부동소숫점을 표현하기 위해서 double이라는 변수를 사용합니다. 이들은 만약 구현을 해야 한다면 64비트 크기의 데이터를 비트 단위로 영역을 나누어서 그 의미를 부여하고 있으므로 과도한 비트 연산을 진행해야할 것입니다.
#include <stdio.h>
#include <string.h>
struct Double
{
unsigned long mant : 52;
unsigned long exp : 11;
unsigned long sign : 1;
} Double;
int main(void)
{
double d;
struct Double s;
d = -1234567890123456;
memcpy(&s, &d, 8);
printf("sign = %u\n", s.sign);
printf("exp = %u\n", s.exp);
printf("mant = %lu\n", s.mant);
return 0;
}
위와 같이 double형의 데이터에 대해서 sign, 지수부, 가수부의 데이터가 어떤형식으로 저장되어 있는 지 알아볼 수 있습니다.
위의 s.sign의 경우는 1비트 값을 가지므로 0 또는 1만 대입할 수 있으며, 그 이외의 데이터를 저장하려고 하위 1비트 이외의 값은 버려집니다.
'Language & etc > C++' 카테고리의 다른 글
Rule of Five? 암시적으로 move 생성자/연산자 생성 (0) | 2022.08.25 |
---|---|
std::Vector push_back() vs emplace_back() (0) | 2022.07.31 |
[컴파일/링킹]에서 본 Static Member Variables, function... (0) | 2022.07.02 |
std::Move, perfect forwarding - ① (0) | 2022.06.19 |
전방 선언 (Forward Declaration) #22.11.22일 복습 (0) | 2022.06.10 |