`sizeof` 연산자(sizeof operator)
sizeof 연산자(sizeof operator)
객체나 타입의 실제 크기를 바이트 단위로 알아야 할 때 쓰는 연산자가 sizeof예요. 객체의 실제 크기가 컴파일 타임에 알고 싶을 때 주로 사용해요.
출처: cppreference
본문
문법
sizeof( type ) |
(1) |
sizeof expression |
(2) |
-
type의 객체 표현(object representation)의 크기를 바이트 단위로 산출해요.
-
그 표현식이 평가된다면, expression의 타입의 객체 표현 크기를 바이트 단위로 산출해요.
| 자리 | 의미 |
|---|---|
| type | type-id(타입 이름 짓기 참고) |
| expression | 우선순위가 sizeof보다 낮지 않은 표현식(예: sizeof a + b는 sizeof (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
몇 가지를 짚어 볼게요. 빈 클래스 Empty는 1이고, sizeof b가 4인 것은 Base& b가 Derived가 아니라 정적 타입 Base를 가리키기 때문이에요. 멤버 순서가 다른 CharCharInt와 IntCharChar는 둘 다 8이지만 CharIntChar는 12로, 패딩이 어떻게 배치되느냐에 따라 크기가 달라져요.
더 알아보기
alignof(C++11): 타입의 정렬 요구사항을 묻는 연산자.sizeof...연산자(C++11): 팩 안의 요소 수를 묻는 연산자.std::numeric_limits: 모든 기본 수치 타입의 속성을 조회하는 인터페이스.