구조체 패딩


Struct Padding

구조체 패딩이란?


구조체에서 각 구성 요소에게 일정한 바이트를 할당하여 블럭 단위로 분할해두는 것


구조체 패딩을 쓰는 이유


구조체 패딩은 한 마디로 일정한 메모리 공간을 할당해서 그 안에 구조체의 구성 요소를 넣어주는 걸 말한다.

그럼 이 때, char과 같은 적은 바이트 수를 가진 자료형은 바이트 수가 남아 메모리 낭비가 아닌가라는 생각이 들게 되고, 이렇게 메모리를 낭비하는 기능이 과연 효율적일까?라는 의문점에 도달하게 된다.

물론 너무 남발하거나, 패딩을 너무 크게 잡아주면 메모리 낭비가 될 수 있다. 하지만 적절하게 사용한다면 처리 속도를 높일 수가 있다.

왜냐하면, CPU가 가장 크기가 큰 자료형을 기준으로 블록을 구성해서 그 블록 별로 처리를 하기 떄문이다.


구조체 패딩 방법

pragma pack


구조체는 기본적으로 구성요소 중 가장 큰 바이트 수를 가진 구성요소의 바이트로 패딩을 설정해준다.

하지만 내가 원하는 바이트로 패딩을 잡는 방법이 있다.

바로 pragma pack이라는 키워드이다. #pragma pack(byte) 이렇게 설정을 하고, byte에 원하는 바이트 수를 설정해주면 해당 바이트 만큼의 패딩이 잡히게 된다.


push


원하는 구조체에만 패딩을 주기 위해 사용한다. 내부 컴파일러에 존재하는 스택에다가 해당 바이트만큼 패딩을 할 것이라고 넣어주는 역할을 한다.

pop


내부 컴파일러 스택에다가 push 해줬던 패딩을 다시 꺼내주는 역할을 한다. 이 역시 원하는 구조체에만 패딩을 주기 위해 사용한다.

push와 pop이 없으면 pragma pack이 적용된 이후로는 전부 해당 바이트만큼 패딩이 적용된다.


예시


1) 자동 패딩

struct S
{
    char a; // 1 byte
    int b;  // 4 byte
    float c;// 4 byte
}; // 총 바이트 : 12 byte

9 바이트가 나와야 하는 것 아닌가? 라고 생각할 수 있지만, 가장 큰 바이트를 가진 int와 float에 의해 자동적으로 패딩이 4바이트로 잡히기 때문에 char 자료형도 4바이트 패딩이 적용되어 총 12 바이트가 나오게 된다.


2) pragma pack

#pragma pack(2)
struct S1
{
    char a; // 1 byte
    int b;  // 4 byte
    float c;// 4 byte
};          // 10 byte

struct S2
{
    char a; // 1 byte
    char b; // 1 byte
}           // 2 byte

struct S3
{
    char a; // 1 byte
    int b;  // 4 byte
    char c; // 1 byte
}           // 8 byte

이번 예시는 2바이트 단위로 패딩을 잡아보았다.

push와 pop이 없기 때문에 pragma pack 아래의 구조체들은 모두 2바이트의 패딩이 적용된다.

S1의 경우, char은 2바이트 패딩이 적용되고, int와 float은 각각 2바이트의 패딩을 2개씩 할당받아 들어간다. 그래서 S1의 총 크기는 10바이트가 된다.

그럼 S2는 어떨까? 4바이트인가? 라고 생각할 수 있지만, 그렇지 않다. S2의 크기는 2바이트이다. 왜냐하면 char 자료형은 1바이트이기 때문에 2바이트의 패딩 안에 모두 넣을 수 있기 때문이다. 그렇기에 2바이트 패딩 하나만으로 충분히 담을 수 있기 때문에 총 바이트 수가 2바이트가 된다.

S3는 충분히 예상 가능할 거라 생각이 된다. 당연히 S3의 경우에는 8바이트 패딩이 잡혀 총 크기가 8바이트가 된다.


3) pragma pack / push / pop

#pragma pack(push, 1)
struct S1
{
    char a; // 1 byte
    int b;  // 4 byte
    float c;// 4 byte
}           // 9 byte
#pragma pack(pop)

struct S2
{
    char a; // 1 byte
    int b;  // 4 byte
    float c;// 4 byte
}           // 12 byte

위의 예시는 push와 pop이 적용되는 걸 볼 수 있다.

S1의 경우에는 1바이트의 패딩이 적용된 것이다. 1바이트의 패딩이 적용됐기 때문에 S1 구조체의 총 크기는 9바이트가 된다.

S2의 경우는, 이전에 pop이 실행됐기 때문에 적용했던 1바이트의 패딩이 아닌, 가장 큰 바이트 단위로 패딩이 적용되어 12바이트가 적용된다.