구조체(struct)는 사용자가 임의로 정의한 연관된 정보(변수)를 이름으로 묶은 것을 의미해요.
struct cat
{
char* name;
uint8_t age;
};
그럼 20000 ( ◡̀_◡́)ᕤ
사실 여기서 끝난다면 글을 작성하지 않았겠지만요!
위와 같이 구조체의 각 필드는 각각의 자료형을 갖으며
해당 자료형의 크기에 따라 구조체의 전체 크기 또한 커져요.
그렇다면 구조체가 메모리를 얼마나 점유하는지 계산해 볼까요?
#include <cstdint>
#include <iostream>
struct foo
{
bool a; // 1 byte
uint32_t b; // 4 byte
};
int main()
{
std::cout << sizeof(foo) << std::endl; // 8
}
각 필드의 크기를 더하면 5(1 + 4)가 나오겠ㅈ..
어라? 어떤 이유에서인지 8이 출력되는 것을 확인할 수 있어요.
운영체제는 메모리를 특정 크기의 단위로 읽는다는 사실 알고 계셨나요?
1 word | |
32bit OS | 4 byte |
64bit OS | 8 byte |
그럼 아래와 같은 구조체를 기준으로 설명을 해볼게요!
struct foo
{
bool a; // 1 byte
uint32_t b; // 4 byte
};
구조체 foo의 메모리 구조를 언뜻 생각해 보면 아래의 표와 같아요.
struct foo | ? | ? | ? | ||||
a | b | ? | ? | ? | |||
1 word1 word | 1 word | ||||||
1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte |
이때 a는 1 word를 사용해서 접근이 가능하지만 b는 2 word가 필요해요.
따라서 메모리의 효율성을 포기하는 대신 CPU의 읽기 명령 cycle을 줄이기 위해
다음과 같이 구조체에 추가하는 잉여 byte를 구조체 패딩(struct padding)이라고 불러요.
struct foo |
|||||||
a | padding | b | |||||
1 word | 1 word | ||||||
1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte |
그렇다면 구조체의 필드 순서를 바꾼다면 어떻게 될까요?
#include <cstdint>
#include <iostream>
struct foo
{
uint32_t b; // 4 byte
bool a; // 1 byte
};
int main()
{
std::cout << sizeof(foo) << std::endl; // 8
}
struct foo |
|||||||
b | a | padding | |||||
1 word | 1 word | ||||||
1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte |
메모리는 효율적으로 사용하면서, 동시에 각 필드를 1 word만으로 사용해서 접근이 가능해ㅈ...
어라..?
사실 효율적으로 필드를 배열하더라도, 구조체 내부에 가장 큰 필드를 기준하는 메모리 정렬로 인해 패딩이 붙어요.
foo의 경우에는 가장 큰 필드인 b의 크기가 4이기 때문에 4N을 맞추기 위해 3 byte가 추가되는 걸 볼 수 있어요.
하지만 때로는 효율적으로 필드를 나열하면 메모리를 절약할 수 있는 경우도 있다는 사실 꼭 알아두세요!
#include <cstdint>
#include <iostream>
struct foo
{
bool a; // 1 byte
bool c; // 1 byte
// padding: 2 byte
uint32_t b; // 4 byte
};
struct bar
{
bool a; // 1 byte
// padding: 3 byte
uint32_t b; // 4 byte
bool c; // 1 byte
// padding: 3 byte
};
int main()
{
std::cout << sizeof(foo) << std::endl; // 8
std::cout << alignof(foo) << std::endl; // 4
std::cout << sizeof(bar) << std::endl; // 12
std::cout << alignof(bar) << std::endl; // 4
}
32bit OS
struct foo |
|||||||
a | c | padding | b | ||||
1 word | 1 word | ||||||
alignment | alignment | ||||||
1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte |
struct bar |
|||||||||||
a | padding | b | c | padding | |||||||
1 word | 1 word | 1 word | |||||||||
alignment | alignment | alignment |
|||||||||
1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte |
64bit OS
struct foo |
|||||||
a | c | padding | b | ||||
1 word | |||||||
alignment | alignment | ||||||
1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte | 1 byte |
struct bar | ? | ? | ? | ? | |||||||||||
a | padding | b | c | padding | ? | ? | ? | ? | |||||||
1 word | 1 word | ||||||||||||||
alignment | alignment | alignment | ? | ? | ? | ? | |||||||||
- | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - |
TIP) 만약 구조체의 메모리 정렬이 OS의 word와 일치한다면 효율이 높아져요.
TIP) packed 지시문을 사용하면 패딩을 강제로 제거할 수 있어요. (GCC, Clang)
#include <cstdint>
#include <iostream>
struct __attribute__((packed)) foo
{
bool a; // 1 byte
uint32_t b; // 4 byte
bool c; // 1 byte
};
int main()
{
std::cout << sizeof(foo) << std::endl; // 6
std::cout << alignof(foo) << std::endl; // 1
}
TIP) pack 전처리기를 사용하면 메모리 정렬을 2^N을 충족하는 임의의 값으로 강제할 수 있어요. (GCC, MSVC)
#include <cstdint>
#include <iostream>
#pragma pack(push, 1)
struct foo
{
bool a; // 1 byte
uint32_t b; // 4 byte
};
#pragma pack(pop)
int main()
{
std::cout << sizeof(foo) << std::endl; // 5
std::cout << alignof(foo) << std::endl; // 1
}
TIP) alignas 키워드를 사용하면 메모리 정렬을 2^N을 충족하는 임의의 값으로 강제할 수 있어요. (C++ 11 표준)
#include <cstdint>
#include <iostream>
struct alignas(1) foo
{
bool a; // 1 byte
// padding 3 byte
uint32_t b; // 4 byte
};
int main()
{
std::cout << sizeof(foo) << std::endl; // 8
std::cout << alignof(foo) << std::endl; // 4
}
다만 보다시피 alignas 키워드는 컴파일러에 따라 지원하지 않아요... C++17 이상 부터는 정식으로 지원해요
Credits
Data structure alignment - Wikipedia
From Wikipedia, the free encyclopedia Way in which data is arranged and accessed in computer memory Data structure alignment is the way data is arranged and accessed in computer memory. It consists of three separate but related issues: data alignment, data
en.wikipedia.org
'프로그래밍 > C&C++' 카테고리의 다른 글
the rule of 0/3/5 (1) | 2025.03.18 |
---|---|
String & SSO (3) | 2025.02.17 |
Union & Bit-field (0) | 2025.02.17 |
Unicode (1) | 2025.01.19 |
Metaprogramming (3) | 2024.12.20 |