구조적 타입

구조적 타입 (Structured Types)

기본 타입 하나로는 큰 데이터를 표현하기 어려운 경우가 많아요. 여러 값을 한 변수에 담아야 할 때 쓰는 게 바로 구조적 타입(structured type) 이에요. 이번 절에서 그 종류와 메모리 배치(layout) 규칙을 살펴볼게요.

출처: 문서

본문

구조적 타입은 하나의 변수에 여러 값을 담을 수 있는 타입이에요. 구조적 타입은 제한 없이 중첩할 수 있어요.

Delphi와 달리 Free Pascal은 모든 구조적 타입에 Packed 키워드를 지원하지는 않아요. 아래 절에서 각 구조적 타입을 다루면서 어떤 타입이 packed 키워드를 지원하는지 언급할게요.

이 절에서 다루는 구조적 타입은 다음과 같아요:

  • Packed 구조적 타입(Packed structured types)
  • 3.3.1 배열(Arrays)
    • 정적 배열(Static arrays)
    • 동적 배열(Dynamic arrays)
    • 동적 배열 타입 호환성(Dynamic array Type compatibility)
    • 동적 배열 생성자(Dynamic array constructor)
    • 동적 배열 상수 표현식(Dynamic array constant expressions)
    • 배열의 packing/unpacking
  • 3.3.2 레코드 타입(Record types)
    • 레코드 레이아웃과 크기(Record layout and size)
    • 주의 및 예제(Remarks and examples)
  • 3.3.3 집합 타입(Set types)
  • 3.3.4 파일 타입(File types)

Packed 구조적 타입

구조적 타입을 선언할 때, 타입 내부 요소의 정확한 메모리 위치를 가정해서는 안 돼요. 컴파일러는 구조의 요소를 메모리에 배치할 때 가장 적합하다고 판단되는 방식으로 배치해요. 즉 요소의 순서는 유지되지만 위치는 보장되지 않고, $PACKRECORDS 지시자에 의해 부분적으로 결정돼요(이 지시자는 Programmer's Guide에서 설명해요).

하지만 Free Pascal은 PackedBitpacked 키워드로 레이아웃을 제어할 수 있게 해줘요. 이 두 단어의 의미는 문맥에 따라 달라요:

  • Bitpacked — 이 경우 컴파일러는 순서형 타입을 비트 경계(bit boundary) 에 정렬하려고 해요(아래에서 설명).
  • PackedPacked 키워드의 의미는 상황에 따라 달라요:
    • MACPAS 모드에서는 Bitpacked 키워드와 동일해요.
    • 다른 모드 + $BITPACKING 지시자가 ON일 때도 Bitpacked 키워드와 동일해요.
    • 다른 모드 + $BITPACKING 지시자가 OFF일 때는 바이트 경계에서의 일반적인 packing을 뜻해요.

바이트 경계에서 packing한다는 건 구조적 타입의 각 새 요소가 바이트 경계에서 시작한다는 뜻이에요. 바이트 packing 메커니즘은 단순해요. 이전 요소의 크기(작은 열거 타입, 부분범위 타입)가 1바이트보다 작아도 컴파일러는 구조의 각 요소를 사용 가능한 첫 번째 바이트 경계에 정렬해요.

비트 packing 메커니즘을 쓸 때는 컴파일러가 각 순서형 타입을 저장하는 데 몇 비트가 필요한지 계산해요. 다음 순서형 타입은 그다음 비는 비트에 저장돼요. 집합(set)·실수(float)·문자열·(bitpacked) 레코드·(bitpacked) 배열·포인터·클래스·객체·프로시저 변수 같은 비순서형 타입(이에 국한되진 않아요)은 사용 가능한 첫 번째 바이트 경계에 저장돼요.

bitpacking의 내부 구조는 불투명(opaque) 하다는 점에 주의하세요. 언제든 바뀔 수 있거든요. 게다가 내부 packing은 컴파일 대상 플랫폼의 엔디언(endianness) 에 의존해서, 플랫폼 간 변환이 불가능해요. 그래서 bitpacked 구조체는 디스크 저장이나 네트워크 전송에는 부적합해요. 다만 그 형식은 GNU Pascal 컴파일러가 쓰는 형식과 동일하며, Free Pascal 팀은 이 호환성을 앞으로도 유지하려 해요.

bitpacked 구조체의 요소에는 몇 가지 제약이 더 있어요:

  • 주소를 가져올 수 없어요 — 비트 크기가 8의 배수이고 요소가 바이트 경계에 저장된 경우는 예외예요.
  • bitpacked 구조체의 요소를 var 매개변수로 쓸 수 없어요 — 비트 크기가 8의 배수이고 바이트 경계에 저장된 경우는 예외예요.

bitpacked 구조체의 요소 크기를 알아내려면 BitSizeOf 함수를 써요. 이 함수는 요소의 크기를 비트 단위로 반환해요. bitpacked가 아닌 타입이나 구조 요소에 대해서는 바이트 단위 크기에 8을 곱한 값을 반환하므로, 그 값은 8*SizeOf와 같아요.

bitpacked 레코드와 배열의 크기에는 제한이 있어요:

  • 32비트 시스템에서 최대 크기는 2^29바이트(512MB)예요.
  • 64비트 시스템에서 최대 크기는 2^61바이트예요.

그 이유는 요소의 offset을 시스템의 최대 정수 크기로 계산해야 하기 때문이에요.

더 알아보기

  • 여러 값을 담는 타입의 기본 개념과 각 구조적 타입의 상세는 매뉴얼 3.3절 전체에서 다뤄요.
  • 타입의 메모리 배치를 다루는 $PACKRECORDS, $BITPACKING 지시자는 Programmer's Guide를 참고하세요.