구조체 패딩
구조체 멤버변수들을 메모리에서 CPU로 읽을 각 시스템의 워드(word) 경계에서 읽어오는 것이 효율적이기 때문에 컴파일러가 (성능상의 이유로)레지스터의 블록에 맞춰 최적화 하는 작업이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <iostream>
using namespace std;
struct Ex1
{
// int = 4byte, double = 8byte
int x, y, z;
double d;
int f;
};
struct Ex2
{
int x, y, z, f;
double d;
};
int main()
{
cout << sizeof(Ex1) << endl; // 32
cout << sizeof(Ex2) << endl; // 24
return 0;
}
|
cs |
위 코드에서 Ex1, Ex2 는 들어있는 정보량이 같은데 각 구조체별 사이즈를 찍어보면 Ex1은 32바이트, Ex2는 24바이트가 나오게 된다.
위와같은 현상이 나타나는 이유는 바로 패딩(Padding) 때문이다.CPU가 메모리에 접근해서 읽을때 1워드 단위로 읽게 된다. 32비트의 경우 4 바이트, 64비트의 경우 8 바이트를 읽게 된다. 그리고 이렇게 읽는 방식때문에 구조가 달라지게 된다.
1
2
3
4
5
|
struct Ex
{
char a, b;
int x;
};
|
cs |
예시로 이런 구조체가 있다고 하면 실제 정보는 6 바이트지만 메모리에는 8바이트를 차지하게 된다.
각 칸을 1바이트라고 하면 위에처럼 담긴다고 생각하지만
이렇게 들어간다. 이는 컴파일러가 자동적으로 패딩을 넣어주는 경우로 CPU가 읽기 쉽게 1워드(4바이트) 단위로 정보를 주는 것이다.
그런데 위치를 바꾸게 되면,
1
2
3
4
5
|
struct Ex {
char a;
int x;
char b;
};
|
cs |
이러면 무려 12바이트를 차지하게 된다. 1워드에 char 하나, 다음 워드에 int, 다음 워드에 char 하나 들어가는 것이다.
패딩을 줄일 수 있는 법
1. 맴버변수를 재배열
[기존 구조체]
1
2
3
4
5
6
7
|
typedef struct {
unsigned int id; // 4bytes
info_t info; // 24bytes
unsigned short height; // 2bytes
float weight; // 4bytes
unsigned short age; // 2bytes
} data_t;
|
cs |
[바이트에 맞게 재배열한 구조체]
1
2
3
4
5
6
7
|
typedef struct {
unsigned int id; // 4bytes
info_t info; // 24bytes
unsigned short height; // 2bytes
unsigned short age; // 2bytes
float weight; // 4bytes
} data_t;
|
cs |
2. "#pragma pack"을 사용
1
2
3
4
5
6
7
8
9
10
11
|
#pragma pack(push, 1)
typedef struct {
unsigned int id; // 4bytes
info_t info; // 24bytes
unsigned short height; // 2bytes
float weight; // 4bytes
unsigned short age; // 2bytes
} data_t;
#pragma pack(pop)
/*--사이즈--*/
sizeof(data_t) = 36
|
cs |
➡️ #pragma pack을 사용하면 패딩없이 36의 크기로 메모리가 잡힌다.
3. 패딩을 명시적으로 삽입
어쩔 수없이 패딩이 생길 거라면 구조체에 패딩을 명시적으로 넣는 것이 좋다.
1
2
3
4
5
6
7
|
typedef struct {
unsigned int id;
info_t info;
unsigned short height;
char unused[2]; //패딩을 명시적으로 삽입
float weight;
} data_t;
|
cs |
[assert()를 사용한 구조체 크기를 확인]
1
2
3
|
#include <assert.h>
assert(sizeof(data_t) == 36);
|
cs |
디버그모드에서 assert함수로 패딩을 잡아낼 수 있다.
특히, 바이트 단위로 저장해서 다른 실행파일과 공유를 해야할 때 위와같이 구조체의 크기를 체크하는 것이 좋다.
출처 및 참고 : https://husk321.tistory.com/265
HyunZzang의 프로그래밍 공간 / 함께 공부해요!!
도움이 되셨다면 "좋아요❤️" 또는 "구독👍🏻" 부탁드립니다 :)