Quick Reference
sizeof는 객체 또는 타입의 바이트 크기를 size_t로 돌려줍니다. 배열이 실제 배열로 남은 선언 위치에서만 원소 수를 계산하고, allocation에는 sizeof *ptr을 씁니다.
int arr[] = {10, 20, 30};
size_t count = sizeof arr / sizeof arr[0];
int *p = malloc(n * sizeof *p);
size_t pointer_bytes = sizeof p; /* 배열이나 원소 수가 아니다. */함수 매개변수의 arr은 이미 포인터이므로 같은 식으로 길이를 구할 수 없습니다. n * sizeof *p를 계산할 때는 곱셈 overflow도 따로 검사합니다.
문법
int arr[10];
size_t count = sizeof arr / sizeof arr[0];이건 배열이 실제 배열로 남아 있는 스코프에서만 맞습니다. 함수 인자로 넘어가면 배열은 포인터처럼 취급되므로 길이 정보가 사라집니다.
그래서 sizeof 카드는 결국 배열 decay 카드와 연결됩니다.
sizeof는 보통 식을 실제로 실행하는 게 아니라, 그 식이 어떤 타입 크기를 가지는지를 묻는 연산으로 읽는 편이 맞습니다.
int x = 0;
size_t n = sizeof(x + 1.0);그래서 sizeof는 "실행 결과"보다 "타입 크기"를 묻는 연산으로 읽는 편이 맞습니다.
다만 VLA(가변 길이 배열)의 크기를 결정하는 operand는 런타임에 평가될 수 있습니다. 부수 효과가 있는 식을 sizeof 안에 넣지 않는 것이 가장 단순한 규칙입니다.
사용 예시
int *p = malloc(sizeof *p * 100);이 패턴이 좋은 이유:
- 타입 이름을 두 번 안 쓴다
- 나중에 포인터 타입이 바뀌어도 크기가 같이 바뀐다
즉 "타입명을 다시 적어서 맞추는 습관"보다 오류 가능성이 낮습니다.
int *p = malloc(sizeof(int *) * 100); /* 잘못된 패턴 */이 코드는 int 원소가 아니라 포인터 크기만큼 잡을 수 있어서 자주 틀립니다.
할당 크기 count * sizeof(*p)도 overflow할 수 있습니다. 외부 입력 count는 count > SIZE_MAX / sizeof(*p)를 먼저 검사하고, malloc(0)의 반환값으로 객체 하나를 얻었다고 가정하지 않습니다.
빠른 점검
- 함수 안에서 배열 길이 계산
sizeof(ptr)를 배열 전체 크기로 착각malloc(sizeof(Type *))처럼 별을 잘못 붙임
void print_all(int arr[]) {
size_t n = sizeof(arr) / sizeof(arr[0]); /* 포인터 크기 기준 */
}주의할 점
sizeof가 배열에서 잘 동작한 경험 때문에 함수 안에서도 같은 방식으로 길이를 구하려 하면 거의 반드시 틀립니다. C에서 배열 길이는 타입 시스템이 끝까지 보존해 주지 않는 정보라는 점을 계속 의식해야 합니다.
참고 링크
2 sources