한양과학기술고등학교

에듀테크 프로젝트 대시보드

구조체 패딩과 메모리 정렬

왜 sizeof(struct)는 필드 크기의 합보다 커질까?

구조체의 각 필드는 메모리 아무 위치에나 놓이지 않는다. CPU가 값을 한 번에 읽고 쓰려면 각 타입은 자신의 정렬 요구사항(alignment) 배수 주소에 놓여야 하고, 컴파일러는 그 사이에 빈 패딩(padding) 바이트를 채워 넣는다. 필드 순서만 바꿔도 구조체 크기가 수십 % 달라질 수 있다.

정렬 요구사항 (x86-64 기준)

대부분의 아키텍처에서 타입의 정렬 요구사항은 자기 자신의 크기와 같다 — 4바이트 int는 4의 배수 주소에, 8바이트 double은 8의 배수 주소에 놓인다.

타입크기정렬 요구사항허용되는 시작 주소
char1B10, 1, 2, 3, 4 ...
short2B20, 2, 4, 6 ...
int / float4B40, 4, 8, 12 ...
long / double / 포인터8B80, 8, 16, 24 ...

구조체 전체도 내부에서 가장 큰 정렬 요구사항의 배수 크기가 되도록 끝에도 패딩이 붙는다 (그래야 이 구조체를 배열로 만들었을 때 두 번째 원소도 정렬이 깨지지 않는다).

예시: 필드 순서가 크기를 바꾼다

struct Bad {
    char  a;   // offset 0, 1B
    // 패딩 3B (int는 4의 배수 주소여야 함)
    int   b;   // offset 4, 4B
    char  c;   // offset 8, 1B
    // 꼬리 패딩 3B (구조체 전체를 4의 배수로)
};  // sizeof(Bad) == 12

struct Good {
    int   b;   // offset 0, 4B
    char  a;   // offset 4, 1B
    char  c;   // offset 5, 1B
    // 꼬리 패딩 2B
};  // sizeof(Good) == 8

필드 두 개는 그대로인데, 큰 타입을 앞에 두는 순서만 바꿨더니 25%가 줄었다. 아래에서 직접 필드를 재배열하며 바이트 단위 레이아웃을 확인해보자.

인터랙티브: 내 구조체 레이아웃 계산기

필드를 추가/삭제/이동하면서 실제 메모리 레이아웃이 어떻게 바뀌는지 확인해보자. 색이 칠해진 칸은 실제 데이터, 빗금 친 빨간 칸은 낭비되는 패딩이다.

-
전체 크기
-
패딩 바이트
-
실 데이터
-
낭비율

배열 arr[1000]로 만들면 이 낭비율만큼 전체 메모리와 캐시 라인 활용률에 그대로 곱해진다 — 원소 하나의 몇 바이트 낭비가 대용량에서는 수십 KB~MB의 손실이 된다.

실전 팁 & 관련 개념

정렬 규칙: "큰 타입부터 작은 타입 순"으로 필드를 배치하면 대부분의 경우 패딩이 최소화된다 (컴파일러가 자동으로 재배치해주지 않는 언어에서는 직접 신경 써야 한다).

강제로 패딩을 없애려면 C에서는 #pragma pack(1)이나 __attribute__((packed))을 쓸 수 있지만, 일부 아키텍처(ARM 등)에서는 비정렬 접근이 느리거나 아예 하드웨어 예외를 일으킬 수 있어 대가가 따른다. 네트워크 패킷이나 파일 포맷처럼 바이트 단위로 규격이 정해진 곳에서 흔히 쓰인다.

다른 학습 페이지와의 차이: 이 페이지는 컴파일러가 단일 구조체 안에서 필드를 정렬 규칙에 맞춰 배치하며 생기는 내부 패딩을 다룬다. 메모리 계층 구조는 CPU 캐시부터 디스크까지 저장 장치의 속도 차이를, 거짓 공유는 여러 스레드가 같은 64B 캐시 라인을 공유할 때 생기는 성능 문제를 다뤄 서로 겹치지 않는다.