[C, C++] 구조체 비트필드로 메모리 용량 확보

필요성

ON/OFF 스위치와 같이 0과 1의 값만 가지는 변수는 C99부터 지원하는 bool 자료형을 사용할 수 있다. 그런데 ON/OFF는 1비트면 충분하지만 bool을 사용하여 1바이트(8비트)나 소모한다. 이때 구조체의 비트필드를 활용하면 1비트만으로 구현이 가능하다.

사용 예

임베디드 제품을 개발하고 있지만 메모리 최적화를 위해서 비트필드를 사용한적은 없다. 그러나 통신을 위해서 사용하고있다. 예를들어 두개의 AP가 UART로 통신하고 있다면 통신 프로토콜을 정의할때 패킷의 사이즈를 정한다. 내가 개발에 참여했던 제품의 경우 보통 패킷 사이즈는 128바이트를 넘지 않기 때문에 패킷의 사이즈가 128바이트라고 하면 128바이트에 signal_1, signal_2, signal_3…과 같이 모든 신호들을 넣어서 보내야 한다. 이때는 128바이트 안에 모든 신호를 다 넣기 위해 비트필드를 이용한다.

사용법

비트필드는 구조체 각 변수에게 몇 비트를 할당해줄지 결정할 수 있다. 변수 뒤에 콜론과 할당할 비트를 적는다.

typedef struct st{
    unsigned char MouseOnOff : 1;
    unsigned char DisplayOnOff : 1;
    unsigned char KeyboardOnOff : 1;
}st;

위처럼 각 변수에게 1비트씩 할당한 구조체와 그렇지 않은 구조체의 사이즈를 비교하면 다음과 같다.

typedef struct st{
    unsigned char MouseOnOff : 1;
    unsigned char DisplayOnOff : 1;
    unsigned char KeyboardOnOff : 1;
}st;

typedef struct st2{
    unsigned char MouseOnOff;
    unsigned char DisplayOnOff;
    unsigned char KeyboardOnOff;
}st2;

int g;
int main(void){
    printf("%d\r\n", sizeof(st)); // print : 1
    printf("%d", sizeof(st2)); // print : 3
}

unsigned char는 1바이트를 가진다. 따라서 st2구조체는 unsigned char가 3개이므로 3바이트를 가진다. 그러나 st구조체는 unsigned char로 선언하더라도 1비트만 할당하기 때문에 3비트를 가진다. 3비트는 나머지 5비트가 패딩 되어 st구조체는 1바이트를 가지게 된다.

주의사항

#include <stdio.h>

typedef struct{
    int testInt : 1;
    long testLong : 1;
    unsigned int testUInt : 1;
}st;

int main(){
    st s = {1, 1, 1};
    printf("%d %ld %d\r\n", s.testInt, s.testLong, s.testUInt); // -1 -1 1
}

위 코드를 실행하면 s.testInt, s.testLong, s.testUInt의 값은 모두 1이 되어야 할것 같지만 s.testInt와 s.testLong은 -1이 출력된다. 이는 int와 long이 양수와 음수 모두 가질 수 있는 signed 자료형이라서 발생하는 문제다. signed는 가장 앞 비트(MSB)를 음수/양수를 표현하는 부호비트로 사용된다. 따라서 출력에 오류가 발생하는 것이다.

Leave a Comment