본문 바로가기

프로그래밍/C&C++

Struct Padding

반응형

구조체(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