Struct
구조체 Struct의 멤버 변수를 메모리에서 CPU로 읽을 때 한번에 읽을 수 있도록, 컴파일러가 레지스터의 블록, Word의 크기(64비트라면 8바이트, 32비트라면 4바이트)에 맞춰 바이트를 패딩시켜주는 최적화 작업을 수행한다. 만약
struct x
{
char a;
int b;
char c;
}
struct x data;
위 구조체의 메모리 크기인 sizeof(data)는 6바이트가 아닌 12바이트이다. 컴파일러가 구조체를 구성하는 멤버들을 가장 크기가 큰 멤버 자료형(여기서는 int)의 배수가 되도록 정렬했기 때문이다. 이 정렬을 위해 의미없는 바이트들을 더해 패딩해준 것이고, a와 c 뒤에 3바이트씩 패딩이 추가된다.
struct x
{
char a;
char c;
int b;
}
하지만 다음과 같이 x를 선언할 경우, 12가 아니라 8이 나온다. 다음과 같이 컴파일러에서 구조체 멤버의 순서에 맞도록 메모리를 할당하여 최적화를 진행했기 떄문이다.
따라서 불필요한 padding 메모리 값을 줄이기 위해서는 타입의 크기가 내림차순이 되도록 코드에서 나열하는 것이 좋다.
또 상속할 때도 생각해야 되는데,
class A
{
int a;
char b;
char c;
int d;
};
class B : public A
{
double e;
};
이때 A의 크기는 4 + 4(b,c 두개) + 4 = 12 바이트를 차지하게 되는데, B에서는 그럼 12 + 8(double) = 20 바이트로 될거라고 생각하겠지만, 실제로는 24바이트이다. 이는 double에 의해 정렬되어 8(a+b+c) + 8(d) + 8(e) = 24로 24바이트를 차지하게 되는 것이다.
참고) 전처리기 #pragma pack(n)
이 전처리기는 정수 n값이 넘을 경우, 정렬(바이트 패딩)을 포기한다는 것이다. n값 이하일 경우에만 정렬하고 n값은 1,2,4,8,16만 유효하다. 디폴트값은 가장 기본 타입이 8바이트기 때문에 n값은 8이다.
Union
공용체(union)과 구조체(struct)는 공용체는 모든 멤버 변수가 하나의 메모리 공간을 공유한다는 점이 다르다.
공용체는 크기가 가장 큰 멤버 변수의 크기로 메모리를 할당받는다. 따라서 모든 멤버변수를 선언하는 것보다 메모리를 절약할 수 있다는 장점이 있다.
공용체는 순서가 규칙적이지 않고 미리 알 수 없는 다양한 타입의 데이터를 저장할 수 있도록 설계된 타입이다. 예를들어 내가 배열로 받을 지, 아니면 각 객체의 이름을 통해 받을 지를 Union을 통해 제어할 수 있다.
struct U
{
union
{
union
{
int a;
int b;
int c;
};
union
{
int arr[3];
};
};
};
다음과 같이 구조체 U안에 union이 있다고 해보자. 사용자는 a에 접근할 때, a에 직접 접근할 수도 있지만 a,b,c와 배열 arr은 같은 union안에 존재하여 메모리를 공유하고 있으므로 arr[0]을 통해 접근할 수도 있다.
Class
기본적으로 멤버변수에 대해서는 Struct와 같은 방식으로(정렬) 메모리가 할당된다. 일반적인 멤버 함수의 경우에는 변수 자체의 메모리에는 관여를 하지 않는다.
class A
{
int a;
char b;
void Func();
}
위 경우에는 클래스 A는 a와 b에대한 메모리만 가지게 되어 클래스 A는 총 8바이트의 메모리 크기를 가지게 된다. 함수의 메모리는 별도의 공간, 모든 클래스 객체가 접근할 수 있는 메모리 공간에 위치하게 된다.
하지만 가상함수의 경우에는 상황이 달라진다. 가상 함수의 경우에는 가상함수 테이블인 vtable이 만들어지고 그 vtable 내의 어떤 함수가 실행될지를 나타낼 포인터가 필요하다. 그 포인터를 가리키는 공간(운영체제에 맞게 4byte 또는 8byte)가 추가로 더 생기게 된다.
class A{
public:
int a;
char b;
virtual void vFunc(){ };
}
위 경우에 만약 x64를 사용중이라면, 메모리 주소는 8byte이므로 가상함수 테이블에 대한 주소도 8byte를 차지하게 된다. 따라서 8byte에 의해 정렬되어 클래스 A의 메모리 크기는 16byte를 차지하게 될 것이다.
'C++' 카테고리의 다른 글
std::vector의 복사 생성자(복사 대입) (6) | 2024.09.16 |
---|---|
MySQL/MariaDB C/C++ 연동 (0) | 2024.04.25 |
함수 호출 규약(function call convention) : _cdecl, _stdcall, _fastcall (1) | 2024.01.27 |