취미생활

[C++] 구조체 비트 필드로 비트 단위 변수 사용하기 본문

컴퓨터/C++

[C++] 구조체 비트 필드로 비트 단위 변수 사용하기

달다달아 2022. 9. 5. 02:07

C++로 개발하다 보면 프로토콜 관련 코딩을 진행할 때 비트단위 변수 제어가 필요한 상황이 자주 생긴다.

 

그럴 때 마다 등장하는게 구조체 비트 필드이다.

 

구조체 비트 필드는 별 거 없다.

 

구조체의 변수들을 비트 필드로 설정해놓은 것이 구조체 비트 필드다.

 

비트 필드는 쉽게 말해서 비트 값을 제한해둔 변수라고 생각하면 된다.

 

예시 코드는 아래와 같다.

//비트 필드 예시 코드
unsigned int _data1:8; // 8bit
unsigned int _data2:4; // 4bit
unsigned int _data3:3; // 3bit

이렇게 비트 필드를 선언할 수 있는데, 정수 자료형은 모두 사용 가능하지만 가급적이면 unsigned int, int, bool을 사용하라고 권장하고 있다.

https://stackoverflow.com/questions/17670436/in-case-of-bit-fields-which-one-is-better-to-use-unsigned-char-or-unsigned-int

 

In case of bit fields, which one is better to use, unsigned char or unsigned int and why?

I just want to know about following structure declarations. Which one is better to use for memory allocation and why? And what about padding in case of unsigned char and unsigned int? struct data{

stackoverflow.com

 

이렇게 비트 필드를 쓰면 좋은 점이 참 많다.

 

특히, 통신 과정에서 프로토콜에 맞춰서 비트 값을 설정해 struct 변수를 만들어 데이터를 주고 받을 때 엄청 편리하다.

 

구조체 비트필드 예시는 아래와 같다.

#include <iostream>

using namespace std;

// 비트 필드 선언
struct Data
{
    unsigned int _uid:4;
    unsigned int _fmt:4;
    unsigned int _ctl:4;
};

// 데이터 입력 코드
void receive_something(Data *rcv)
{
    rcv->_uid = 0b0101;
    rcv->_fmt = 0x3;
    rcv->_ctl = 15;
    return;

}

int main()
{
    Data data;
    receive_something(&data);
    // 데이터 출력 코드
    cout << sizeof(data) << endl;
    cout << data._uid << endl;
    cout << data._fmt << endl;
    cout << data._ctl << endl;

    return 1;
}

main이 시작되면 Data 변수를 하나 만든 뒤 receive_something 함수로 데이터를 받아온다.

그리고 값을 출력 해준다.

 

여기서 receive_something 부분에 rcv 함수를 써주면 TCP/IP 통신에서 쓰는 거고

register 설정 함수를 써주면 임베디드에서 쓰는 만능 코드가 된다.

 

참고로 비트 단위 컨트롤이기 때문에 오버플로우가 상당히 많은데, 프로토콜이 딱 정해져 있는 게 아니라면 값 사이에 안쓰는 영역을 넣는 것도 가능하다.

 

struct Data
{
    unsigned int _uid:4;
    unsigned int _nouse:8;
    unsigned int _fmt:4;
    unsigned int _ctl:4;
};
// 이것도 됨!
struct Data
{
    unsigned int _uid:4;
    unsigned int :8;
    unsigned int _fmt:4;
    unsigned int _ctl:4;
};

 이런 식으로 uid 값 이후에 8개 비트의 공백 공간을 둘 수도 있다.

아무 것도 안넣어도 빌드는 가능하지만 코드가 보기 힘들어지니 안쓴다는 이름으로 넣어두는 게 좋을 듯하다.

 

참고로 비트 필드에 0을 집어넣을 수도 있다.

struct Data
{
    unsigned int _uid:4;
    unsigned int :0;
    unsigned int _fmt:4;
    unsigned int _ctl:4;
};
// 이건 안됨!
struct Data
{
    unsigned int _uid:4;
    unsigned int a:0;
    unsigned int _fmt:4;
    unsigned int _ctl:4;
};

Linked in C++ 시험에서 처음 본 기능인데,

비트 필드에 변수 이름을 안넣고 필드만 선언해두면 빌드가 되긴 된다.

이러면 변수로 잡힐 것도 없고 비트 필드도 없는 거니까 코드는 별로지만 컴파일러에서 문제 삼지는 않는 듯... 

 

비트 필드에 대한 자세한 내용은 마이크로 소프트 레퍼런스 문서 참조하면 좋다.

 

다음 번엔 공용체(union) 비트 필드의 활용에 대해 써보겠다.

 

 

참고 자료

https://docs.microsoft.com/ko-kr/cpp/cpp/cpp-bit-fields?view=msvc-170 

 

C++ 비트 필드

자세한 정보: C++ 비트 필드

docs.microsoft.com

 

Comments