`sizeof` 연산자(sizeof operator)

sizeof 연산자(sizeof operator)

객체나 타입의 실제 크기를 바이트 단위로 알아야 할 때 쓰는 연산자가 sizeof예요. 객체의 실제 크기가 컴파일 타임에 알고 싶을 때 주로 사용해요.

출처: cppreference

본문

문법

sizeof( type ) (1)
sizeof expression (2)
  1. type의 객체 표현(object representation)의 크기를 바이트 단위로 산출해요.

  2. 그 표현식이 평가된다면, expression의 타입의 객체 표현 크기를 바이트 단위로 산출해요.

자리 의미
type type-id(타입 이름 짓기 참고)
expression 우선순위가 sizeof보다 낮지 않은 표현식(예: sizeof a + bsizeof (a + b)가 아니라 (sizeof a) + b로 해석)

sizeof 표현식의 결과는 std::size_t 타입의 상수 표현식이에요.

주의할 점(Notes)

컴퓨터 아키텍처에 따라 바이트는 8비트 이상으로 구성될 수 있고, 정확한 비트 수는 CHAR_BIT에 기록돼요.

다음 sizeof 표현식은 항상 1로 평가돼요.

  • sizeof(char)
  • sizeof(signed char)
  • sizeof(unsigned char)
  • sizeof(std::byte) (C++17부터)
  • sizeof(char8_t) (C++20부터)

sizeof는 함수 타입, 불완전 타입, 또는 비트 필드 lvalue(C++11까지)/glvalue(C++11부터)에는 쓸 수 없어요.

참조 타입에 적용하면 결과는 그 참조된 타입의 크기예요.

클래스 타입에 적용하면 결과는 그 클래스의 완전한 객체가 차지하는 바이트 수로, 그 객체를 배열에 배치하기 위해 필요한 추가 패딩을 포함해요. 잠재적으로 겹치는 부분 객체(potentially-overlapping subobject)가 차지하는 바이트 수는 그 객체의 크기보다 작을 수 있어요.

sizeof의 결과는 빈 클래스 타입에 적용해도 항상 0이 아니에요.

표현식에 적용하면 sizeof는 그 표현식을 평가하지 않아요(즉 그 표현식은 비평가 피연산자(unevaluated operand)이고)(C++11부터), 그 표현식이 다형적 객체를 가리키더라도 결과는 그 표현식의 정적 타입의 크기예요. lvalue-to-rvalue, 배열-포인터, 함수-포인터 변환은 수행되지 않아요. 다만 prvalue 인자에 대해서는 (형식적으로) 임시 객체 구체화가 수행되며, 인자가 파괴 가능(destructible)하지 않으면 프로그램은 ill-formed예요. (C++17부터)

예제

이 예제의 출력은 64비트 포인터와 32비트 int(LP64 또는 LLP64)를 쓰는 시스템을 기준으로 한 것이에요. 구체적으로 어떤 크기가 나오는지 확인해 볼게요.

#include <cstdlib>
#include <iostream>

struct Empty          { };
struct Base           { int a; };
struct Derived : Base { int b; };
struct Bit            { unsigned bit: 1; };
struct CharChar       { char c; char c2; };
struct CharCharInt    { char c; char c2; int i; };
struct IntCharChar    { int i;  char c;  char c2; };
struct CharIntChar    { char c; int i;   char c2; };
struct CharShortChar  { char c; short s; char c2; };

int main()
{
    Empty e;
    Derived d;
    Base& b = d;
    [[maybe_unused]] Bit bit;
    int a[10];

    auto f = [&]() { return sizeof(int[10]) == sizeof a ? throw 1 : e; };
//  f(); // 반환 타입은 Empty이지만, 항상 1을 던진다

    auto println = [](auto rem, std::size_t size) { std::cout << rem << size << '\n'; };

    println( "1) sizeof empty class:              ", sizeof e                     );
    println( "2) sizeof pointer:                  ", sizeof &e                    );
    println( "3) sizeof(Bit) class:               ", sizeof(Bit)                  );
    println( "4) sizeof(int[10]) array of 10 int: ", sizeof(int[10])              );
    println( "5) sizeof a        array of 10 int: ", sizeof a                     );
    println( "6) length of array of 10 int:       ", ((sizeof a) / (sizeof *a))   );
    println( "7) length of array of 10 int (2):   ", ((sizeof a) / (sizeof a[0])) );
    println( "8) sizeof the Derived class:        ", sizeof d                     );
    println( "9) sizeof the Derived through Base: ", sizeof b                     );
    println( "A) sizeof(unsigned):                ", sizeof(unsigned)             );
    println( "B) sizeof(int):                     ", sizeof(int)                  );
    println( "C) sizeof(short):                   ", sizeof(short)                );
    println( "D) sizeof(char):                    ", sizeof(char)                 );
    println( "E) sizeof(CharChar):                ", sizeof(CharChar)             );
    println( "F) sizeof(CharCharInt):             ", sizeof(CharCharInt)          );
    println( "G) sizeof(IntCharChar):             ", sizeof(IntCharChar)          );
    println( "H) sizeof(CharIntChar):             ", sizeof(CharIntChar)          );
    println( "I) sizeof(CharShortChar):           ", sizeof(CharShortChar)        );
    println( "J) sizeof f():                      ", sizeof f()                   );
    println( "K) sizeof Base::a:                  ", sizeof Base::a               );

//  println( "sizeof function:        ", sizeof(void()) ); // 오류
//  println( "sizeof incomplete type: ", sizeof(int[])  ); // 오류
//  println( "sizeof bit-field:       ", sizeof bit.bit ); // 오류
}

가능한 출력:

1) sizeof empty class:              1
2) sizeof pointer:                  8
3) sizeof(Bit) class:               4
4) sizeof(int[10]) array of 10 int: 40
5) sizeof a        array of 10 int: 40
6) length of array of 10 int:       10
7) length of array of 10 int (2):   10
8) sizeof the Derived class:        8
9) sizeof the Derived through Base: 4
A) sizeof(unsigned):                4
B) sizeof(int):                     4
C) sizeof(short):                   2
D) sizeof(char):                    1
E) sizeof(CharChar):                2
F) sizeof(CharCharInt):             8
G) sizeof(IntCharChar):             8
H) sizeof(CharIntChar):             12
I) sizeof(CharShortChar):           6
J) sizeof f():                      1
K) sizeof Base::a:                  4

몇 가지를 짚어 볼게요. 빈 클래스 Empty1이고, sizeof b4인 것은 Base& bDerived가 아니라 정적 타입 Base를 가리키기 때문이에요. 멤버 순서가 다른 CharCharIntIntCharChar는 둘 다 8이지만 CharIntChar12로, 패딩이 어떻게 배치되느냐에 따라 크기가 달라져요.

더 알아보기

  • alignof(C++11): 타입의 정렬 요구사항을 묻는 연산자.
  • sizeof... 연산자(C++11): 팩 안의 요소 수를 묻는 연산자.
  • std::numeric_limits: 모든 기본 수치 타입의 속성을 조회하는 인터페이스.