개요
구조체는 비슷한 개념의 변수들을 묶어서 나타낼 수 있는 문법으로, 구조체 이름을 통해 마침표(.) 연산자로 각 멤버에 접근할 수 있도록 해준다.
이번에는 구조체에 대해 여러가지로 알아보자
구조체
만약 'Player' 를 표현하고 싶을 때 위와 같이 구조체로 묶는 것이 더 효과적으로 의미를 나타낼 수 있다.
다만 이렇게 이름을 묶는 효과 외에도 다른 효과가 있다.
구조체 안의 변수들은 메모리 상에서 연달아서 배치되기 때문에, 캐시 라인을 가져올 때 구조체의 여러 멤버가 함께 로딩될 가능성이 높아져 접근 속도가 개선될 수 있다.
구조체의 크기와 패딩
구조체의 크기는 어떻게 구할까?
struct Test1
{
char a;
int b;
char c;
};
struct Test2
{
char a;
char b;
int c;
};
int wmain(void)
{
cout << sizeof(Test1) << '\n';
cout << sizeof(Test2) << '\n';
return 0;
}
Test1과 Test2의 크기는 같을까?
실제로 출력했을 때는 위와 같이 값이 다르게 나온다.
이는 구조체의 패딩 때문이다.
구조체의 패딩은 CPU가 해당 메모리를 쉽게 접근할 수 있도록 정렬해주는 것이다.
x86아키텍쳐는 4바이트, x64아키텍쳐는 8바이트를 한번에 읽는데, 만약 어떠한 자료형이 경계에 걸쳐서 존재한다면 한번에 읽을 수 있는 자료를 나눠서 읽게 된다.
이는 x86에서 long long을 다루는 예시를 통해 확인해볼 수 있다.
int a = 10;
006B1006 C7 45 FC 0A 00 00 00 mov dword ptr [a],0Ah
int b = a + 100;
006B100D 8B 45 FC mov eax,dword ptr [a]
006B1010 83 C0 64 add eax,64h
006B1013 89 45 F8 mov dword ptr [b],eax
long long c = 10;
006B1016 33 C9 xor ecx,ecx
006B1018 C7 45 F0 0A 00 00 00 mov dword ptr [c],0Ah
006B101F 89 4D F4 mov dword ptr [ebp-0Ch],ecx
long long d = c + 100;
006B1022 8B 55 F0 mov edx,dword ptr [c]
006B1025 83 C2 64 add edx,64h
006B1028 8B 45 F4 mov eax,dword ptr [ebp-0Ch]
006B102B 83 D0 00 adc eax,0
006B102E 89 55 E8 mov dword ptr [d],edx
006B1031 89 45 EC mov dword ptr [ebp-14h],eax
longlong은 8바이트 자료형이지만, x86은 한번에 dword ptr(4바이트)를 읽을 수 있기 때문에 int형과 다르게 두번에 나눠서 값을 읽어들이는 모습이다.
결론적으로 자료형을 정렬하는 기준은 CPU가 변수를 가장 효과적으로 접근하는 것이고, 이는 해당 자료형의 크기의 경계에 세우는 것과 같다.
만약 이러한 정렬이 깨진다면 성능이 저하되거나, 아키텍처에 따라 예외가 발생할 수 있다.
다시 예시
struct A
{
char a;
short b;
int c;
char d;
char e;
int f;
};
이제 구조체 A의 크기를 적절하게 유추해볼 수 있다.
위와 같은 구조로 패딩이 이루어져 크기는 총 16바이트가 된다.
추가적으로 구조체 전체 크기는 가장 큰 멤버의 배수로 맞춰진다.
이는 구조체를 배열로 선언했을 때 각 요소의 정렬을 유지하기 위함이며, 동시에 멤버들의 정렬 규칙을 유지하기 위해서이기도 하다.
따라서 char, int 요소가 있는 구조체와 int, char가 있는 구조체는 내부 배치와 패딩의 차이는 있지만, 결과적으로 크기는 동일하게 8바이트가 된다.
alignas, aligned_malloc
https://basaeng.tistory.com/32
컴퓨터의 CPU (3) - 캐시 메모리
https://basaeng.tistory.com/27 컴퓨터의 CPU (2) - 레지스터https://basaeng.tistory.com/7 컴퓨터의 CPU (1)메인 메모리를 알아봤으니 다음은 CPU이다.구매한 CPU는 가장 보급, 엔트리 급으로 많이 팔리는 라이젠 7500f
basaeng.tistory.com
alignas와 alinged_malloc에 대한 이해를 위해서는 먼저 캐시 메모리에 대한 이해가 필요하다.
RAM에서 캐시 메모리로 데이터를 불러올 때는 캐시라인 단위로 불러온다.
캐시라인은 64바이트 크기이기 때문에 만약 가져오려는 데이터가 캐시라인 경계에 걸쳐있다면 이전의 CPU가 레지스터에서 데이터를 여러번 불러와서 처리했듯이 캐시라인을 여러 줄을 불러와야 할 수 있다.
특히 malloc으로 할당받은 동적메모리는 기본적으로 x86은 8바이트, x64는 16바이트에 맞춰 정렬되기 때문에 항상 같은 캐시라인에 데이터가 존재한다는 보장이 없다.
따라서 이러한 경우에 aligned_malloc을 사용해볼 수 있다.
https://learn.microsoft.com/ko-kr/cpp/c-runtime-library/reference/aligned-malloc?view=msvc-170
_aligned_malloc
자세한 정보: _aligned_malloc
learn.microsoft.com
alignas는 데이터를 정렬하는 기준을 정할 수 있다. 다만 alignas를 지정한다고, aligned_malloc이 자동으로 되는 것은 아니다.
https://learn.microsoft.com/ko-kr/cpp/cpp/alignas-specifier?view=msvc-170
alignas(C++)
다음에 대해 자세히 알아보세요. alignas 지정자
learn.microsoft.com
pragma pack
추가적으로 pragma pack이라는 것이 있다.
https://learn.microsoft.com/ko-kr/cpp/preprocessor/pack?view=msvc-170
팩 pragma
Microsoft C/C++의 pack pragma 지시문에 대해 자세히 알아보기
learn.microsoft.com
#pragma pack(n)은 구조체 멤버 간의 정렬 단위(alignment 단위) 를 n 바이트로 강제로 지정한다.
프로젝트의 속성 페이지에서 적용하는 것은 프로젝트 전체의 구조체 패딩 설정이라면 pragma pack은 지역적인 구조체 패딩 설정이다.
데이터를 아껴야 하는 네트워크용 구조체 등에서 사용할 수 있다.
'C, C++ > C, C++ 잡지식' 카테고리의 다른 글
| CreateThread와 _beginthreadex 간단하게 알아보기 (0) | 2025.10.08 |
|---|---|
| C++ 캐스팅 연산자 (0) | 2025.06.14 |
| 가상 함수 virtual (1) | 2025.06.06 |
| malloc과 new, free와 delete (2) | 2025.05.31 |
| 동적할당 분석해보기(1) (0) | 2025.05.01 |