C 언어에서 구조체(struct)는 다른 구조체와 다양한 데이터 타입을 포함할 수 있습니다. 그러나 구조체 내 필드의 배치가 구조체의 크기와 정렬에 영향을 미칠 수 있습니다. 컴파일러는 가장 큰 필드에 대해 정렬(alignment)을 준수하기 위해 추가 바이트(padding)를 추가합니다. 이는 성능과 프로세서의 올바른 작동을 위해 중요합니다.
구조체가 중첩된 구조체를 포함하는 경우 정렬은 재귀적으로 적용됩니다:
#pragma pack 또는 GCC/Clang의 __attribute__((packed))).예제:
#include <stdio.h> struct Inner { char c; int x; }; struct Outer { char a; struct Inner b; short s; }; int main() { printf("sizeof(struct Inner) = %zu\n", sizeof(struct Inner)); printf("sizeof(struct Outer) = %zu\n", sizeof(struct Outer)); return 0; } // sizeof(struct Inner) = 8 (64비트에서), sizeof(struct Outer) = 16 또는 24
pack과 packed를 사용하면 정렬을 무시하여 크기를 줄일 수 있지만, 이는 일부 플랫폼(ARM, DSP 등)에서 성능을 떨어뜨리거나 오류를 일으킬 수 있습니다.
질문: 동일한 구조체의 크기가 모든 플랫폼에서 동일하다고 보장할 수 있나요?
답변: 아니요! C 표준은 동일한 정렬, 바이트 순서(endian)를 보장하지 않으며, 필드 간 및 구조체 끝에 padding을 "추가"할 수 있습니다. 구조체의 이진 호환성을 위해서는 정렬을 수동으로 관리하고 각 대상 플랫폼에서 항상 sizeof를 명시적으로 테스트해야 합니다.
예제:
struct Data { char c; int x; }; // sizeof(Data)는 일반적으로 64비트에서 8, 32비트에서 5 또는 8
역사
마이크로컨트롤러(ARM)와 PC 간에 이진 프로토콜을 통해 구조체를 교환할 때 ARM에서 전송된 데이터가 PC에서 예상과 일치하지 않았습니다 — 패딩과 바이트 순서가 달라서입니다. 이로 인해 잘못된 매개변수가 디코드되어 장치 제어의 물리적 오류를 초래했습니다.
역사
네트워크 프로토콜에서 데이터 전송 속도를 높이기 위해 packed-구조체를 추가했지만 정렬 없는 플랫폼에서 개별 필드가 작동하지 않는다는 것을 간과했습니다(프로세서가 미스 정렬 액세스를 지원하지 않았음). 최종 결과: 네트워크 패킷 작업 중 하드웨어 예외 발생.
역사
서버가 구조체 레코드로 구성된 외부 파일을 처리하고 있었습니다. 컴파일러 업데이트 후 구조체의 크기가 변경되었습니다(다른 정렬). 파일의 이전 데이터가 올바르게 읽히지 않게 되었고 일부 정보는 "손상된" 상태가 되었습니다.