Tips

[C/C++] 구조체 bitfield 멤버 변수 선언 ( ':' )

OZ1NG 2022. 7. 19. 13:58

[*] tcmalloc 코드를 분석하다가 Span 구조체의 멤버 변수 선언부에 `:`으로 신기하게 변수가 선언된 부분이 있어서 찾아보다가 알게된 bitfield에 대해 정리해봤따.

 

[*] bitfield?

C/C++ 구조체에 있는 문법으로 특정 변수의 크기를 비트 단위로 정할 때 사용한다.

struct {
    unsigned int a : 16;
    unsigned int b : 16;
    unsigned short c;
} typedef test;

위와 같이 선언한다면 a와 b 변수는 원래는 4바이트의 크기를 갖는 unsigned int 형이지만 16비트로 크기 제한을 걸었기
때문에 실제로는 2바이트의 크기만을 갖게 된다. (근데 타입은 유지함..)

이 경우 a와 b 변수는 unsigned short int 형으로 변환된다.

 

비트 단위는 2^n 단위로 설정할 수 있다.

 

[*] 사용 목적

struct {
    unsigned int a : 2;
    unsigned int b : 1;
} typedef test;

예를 들어 2비트 또는 1비트만 필요한 변수라면 위와 같이 선언하여 메모리 낭비를 최소로 만들 수 있다. (극한의 효율...)

 

[*] 테스트 코드

// unsigned int  refcount : 16; 이런 문법 테스트
#include <stdio.h>
#include <stdlib.h>

#define type(x) _Generic((x),                                                     \
        _Bool: "_Bool",                  unsigned char: "unsigned char",          \
         char: "char",                     signed char: "signed char",            \
    short int: "short int",         unsigned short int: "unsigned short int",     \
          int: "int",                     unsigned int: "unsigned int",           \
     long int: "long int",           unsigned long int: "unsigned long int",      \
long long int: "long long int", unsigned long long int: "unsigned long long int", \
        float: "float",                         double: "double",                 \
  long double: "long double",                   char *: "char *",                 \
       void *: "void *",                         int *: "int *",                  \
      default: "unknown")

struct {
    unsigned int a : 16;
    unsigned int b : 16;
    unsigned short c;
} typedef test;

struct {
    unsigned int a : 16;
    unsigned short c;
    unsigned int b : 16;
} typedef test2;

struct {
    unsigned short c;
    unsigned int a : 16;
    unsigned int b : 16;
} typedef test3;

int main(){

    test *buf = malloc(sizeof(test));
    test2 *buf2 = malloc(sizeof(test2));
    test3 *buf3 = malloc(sizeof(test3));
    
    buf->a = 0x1111;
    buf->b = 0x2222;
    buf->c = 0x3333;

    buf2->a = 0x1111;
    buf2->b = 0x2222;
    buf2->c = 0x3333;
    
    buf3->a = 0x1111;
    buf3->b = 0x2222;
    buf3->c = 0x3333;
    // break point
    printf("value : %p, type : %s\n", buf->a, type(buf->a));

    return 0;
}
oz1ng@LAPTOP-6F0C4A2N:/mnt/c/Users/ghdxo/Desktop/oz1ng_Lab/tcmalloc/test$ ./colon_test
value : 0x1111, type : unsigned short int

[*] 메모리 확인

pwndbg> x/20gx 0x405290
0x405290:       0x0000000000000000      0x0000000000000021
0x4052a0:       0x0000333322221111      0x0000000000000000
0x4052b0:       0x0000000000000000      0x0000000000000021
0x4052c0:       0x0000222233331111      0x0000000000000000
0x4052d0:       0x0000000000000000      0x0000000000000021
0x4052e0:       0x0000222211113333      0x0000000000000000
0x4052f0:       0x0000000000000000      0x0000000000020d11
0x405300:       0x0000000000000000      0x0000000000000000
0x405310:       0x0000000000000000      0x0000000000000000
0x405320:       0x0000000000000000      0x0000000000000000

테스트 코드에서 break point 부분까지 실행 후 buf, buf2, buf3의 값을 확인한 모습이다.

unsigned int형이지만 실제로는 unsigned short int와 똑같이 작동하는 것을 볼 수 있다.

 

[*] 주의

- sizeof의 인자로 비트 필드 변수는 들어갈 수 없다.

 

[*] 참고

- https://stackoverflow.com/questions/4706584/what-does-this-mean-in-c-int-a16

 

what does this mean in c int a:16;?

Possible Duplicate: What does 'unsigned temp:3' mean? please what does this notation mean int a:16; I found it is code like this and it does compile. struct name { int ...

stackoverflow.com