16. C++ sizeof 연산자

C++ sizeof 연산자

1. 개요

1.1 문서 개요

이 문서는 C++에서 제공하는 sizeof 연산자에 관해 설명합니다. sizeof는 컴파일 타임에 객체나 타입의 메모리 크기를 바이트 단위로 반환하는 연산자입니다. 해당 연산자는 메모리 최적화, 자료구조 설계, 버퍼 크기 계산 등 다양한 목적으로 사용되며, C++ 프로그래밍에서 데이터 크기에 민감한 시스템이나 네이티브 레벨 프로그래밍에서 자주 활용됩니다.

2. 내용

2.1 sizeof 연산자의 기본 개념과 특징

sizeof는 타입 혹은 변수의 메모리 크기를 바이트 단위로 계산합니다. 컴파일 타임에 평가되므로 런타임 비용이 없으며, 리터럴 상수로 취급됩니다.

2.1.1 기본 문법

sizeof(type)
sizeof expression

두 가지 형식 모두 사용 가능하며, 타입에 대해서는 괄호가 필수이고, 변수에 대해서는 선택입니다.

int a = 10;
std::cout << sizeof(int);   // 4 (일반적인 32비트 시스템 기준)
std::cout << sizeof a;      // 4

2.1.2 반환 타입

sizeof 연산의 반환 타입은 size_t입니다. 이는 <cstddef> 헤더에서 정의된 부호 없는 정수 타입입니다.

#include <cstddef>

size_t size = sizeof(double);

2.2 다양한 자료형에 대한 sizeof 결과

sizeof는 기본 자료형, 사용자 정의 자료형, 배열, 포인터 등 다양한 타입에 적용 가능합니다.

2.2.1 기본 자료형

std::cout << sizeof(char);      // 1
std::cout << sizeof(int);       // 4
std::cout << sizeof(float);     // 4
std::cout << sizeof(double);    // 8

2.2.2 배열

배열의 크기를 구할 때 sizeof는 전체 배열의 바이트 수를 반환합니다. 이를 이용해 배열의 요소 개수를 계산할 수 있습니다.

int arr[10];
std::cout << sizeof(arr);               // 40 (10 * 4)
std::cout << sizeof(arr) / sizeof(int); // 10

2.2.3 포인터

포인터 변수에 대해 sizeof를 적용하면, 해당 포인터의 크기(주소를 저장하는 데 필요한 크기)를 반환합니다. 일반적으로 64비트 시스템에서는 8바이트입니다.

int* ptr;
std::cout << sizeof(ptr); // 8 (64비트 시스템 기준)

2.3 구조체와 클래스에서의 sizeof

2.3.1 구조체와 클래스의 메모리 구조

sizeof는 구조체나 클래스에 적용될 경우 멤버들의 크기를 합산한 후 정렬(padding)을 고려한 전체 크기를 반환합니다.

2.3.1.1 패딩 예시
struct A {
    char a;
    int b;
};

std::cout << sizeof(A); // 8 (패딩 포함)

이 경우 char(1바이트) 다음에 3바이트의 패딩이 삽입되고, 그 다음 int(4바이트)가 위치하여 총 8바이트가 됩니다.

2.3.2 패킹을 통한 구조체 크기 조절

컴파일러 지시자(pragma pack)를 통해 구조체의 패딩을 조절할 수 있습니다.

#pragma pack(1)
struct B {
    char a;
    int b;
};
#pragma pack()

std::cout << sizeof(B); // 5 (패딩 없음)

2.4 sizeof와 동적 할당 객체

동적으로 할당된 객체의 크기는 sizeof로 직접 알 수 없습니다. 해당 연산자는 포인터 자체의 크기만 반환하며, 포인터가 가리키는 실제 메모리 블록의 크기는 추적되지 않습니다.

int* p = new int[10];
std::cout << sizeof(p); // 8 (포인터 크기)

배열의 전체 크기를 알기 위해서는 별도의 추적 관리가 필요합니다.

2.5 sizeof와 함수

2.5.1 함수에는 적용 불가

sizeof는 함수 자체에는 적용할 수 없습니다.

void func();
std::cout << sizeof(func); // 오류 발생

2.5.2 함수 포인터는 적용 가능

void func() {}

std::cout << sizeof(&func); // 함수 포인터 크기 반환

2.6 sizeof와 참조

참조 타입은 내부적으로 실제 객체를 대체하지 않으므로, 참조에 sizeof를 적용하면 해당 참조가 가리키는 대상의 크기를 반환합니다.

int x = 100;
int& ref = x;
std::cout << sizeof(ref); // 4 (int의 크기)

2.7 sizeof와 사용자 정의 연산자 오버로딩

sizeof는 컴파일 타임 연산자이기 때문에 오버로딩할 수 없습니다. 또한, 임의의 사용자 정의 타입에 대해 sizeof를 사용해도 해당 타입 내부의 멤버 크기와 정렬에 따라 자동 계산됩니다.

3. 마무리

sizeof 연산자는 타입이나 객체의 메모리 크기를 컴파일 타임에 확인할 수 있는 정적 도구로, 메모리 레이아웃 이해와 최적화에 핵심적인 역할을 수행합니다. 배열, 구조체, 포인터 등 다양한 데이터 유형에 대해 동작하며, 정렬과 패딩이 결과에 영향을 줄 수 있습니다. 다만, 런타임 동적 할당 영역의 실제 크기는 sizeof로는 확인할 수 없으므로, 동적 객체 관리에는 별도의 메커니즘이 요구됩니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

error: Content is protected !!
위로 스크롤