레코드 타입
레코드 타입 (Record types)
Free Pascal은 고정 레코드와 가변 부분(variant part)이 있는 레코드를 지원해요. 레코드 타입의 문법 다이어그램은 아래와 같아요.
출처: Record types
본문
다음은 유효한 레코드 타입 선언들이에요.
Type
Point = Record
X,Y,Z : Real;
end;
RPoint = Record
Case Boolean of
False : (X,Y,Z : Real);
True : (R,theta,phi : Real);
end;
BetterRPoint = Record
Case UsePolar : Boolean of
False : (X,Y,Z : Real);
True : (R,theta,phi : Real);
end;
가변 부분(variant part)은 레코드에서 마지막에 와야 해요. case 문장의 선택적 식별자는 태그 필드(tag field) 값에 접근하는 데 쓰이는데, 이 값은 기본적으로 프로그래머에게 보이지 않아요. 이 식별자로 어떤 variant가 현재 활성화되어 있는지 알 수 있죠. 사실상 레코드에 새 필드를 도입하는 셈이에요.
Remarks: variant 부분은 중첩할 수 있어요. 예를 들어:
Type
MyRec = Record
X : Longint;
Case byte of
2 : (Y : Longint;
case byte of
3 : (Z : Longint);
);
end;
레코드 레이아웃과 크기
레코드의 레이아웃과 크기는 다섯 가지 요소의 영향을 받아요.
- 필드의 크기
- 플랫폼에 의존하는 필드 타입의 정렬(alignment) 요구사항. 레코드 안의 타입 정렬 요구사항은 별도 변수로 쓸 때와 다를 수 있고, 필드 위치가 타입의 정렬 요구사항에 영향을 줄 수도 있어요.
- 현재 활성화된
{$ALIGN N}또는{$PACKRECORDS N}설정. (이 둘은 서로를 덮어써서 마지막에 지정된 것이 활성화돼요. 다만 정확히 같은 인자를 받지는 않으니 프로그래머 매뉴얼을 확인하세요.) - 현재 활성화된
{$CODEALIGN RECORDMIN=X}설정 - 현재 활성화된
{$CODEALIGN RECORDMAX=X}설정
레코드의 variant 부분 레이아웃과 크기는, variant 부분을 첫 번째 요소가 태그 필드 타입의 필드인 레코드 타입의 필드로 대체한 뒤(태그 필드에 식별자가 선언된 경우) 가장 큰 variant의 요소들을 이어 붙인 것으로 결정돼요.
레코드에서 필드 F2의 오프셋은 이전 필드 F1의 오프셋과 F1 크기의 합을, F2의 요구 정렬 배수로 올림한 값이에요. 이 요구 정렬은 다음과 같이 계산돼요.
- 요구 정렬은 필드 타입의 기본 정렬로 시작하고, 이 타입이 레코드에 나타난다는 사실과 레코드 안 필드 위치에 따라 조정될 수 있어요.
- 요구 정렬이 현재 활성화된
{$CODEALIGN RECORDMIN=X}보다 작으면 이 X 값으로 바꿔요. - 현재
{$ALIGN N}또는{$PACKRECORDS N}설정이 숫자 값이면: 요구 정렬이 N보다 크면 N으로 바꿔요. 즉 N이 1이면 모든 필드가 서로 바로 옆에 배치돼요. RESET또는DEFAULT: 결과 요구 정렬은 타깃에 의존적이에요.C: 요구 정렬은 현재 플랫폼의 공식 ABI 규칙에 따라 조정돼요.POWER/POWERPC,MAC68K: (클래식) Macintosh PowerPC 또는 Macintosh 680x0 플랫폼의 공식 ABI 규칙에 따라 정렬 값이 조정돼요.
레코드의 크기는 레코드 마지막 필드의 오프셋과 이 필드 크기의 합을, 레코드의 요구 정렬 배수로 올림한 값이에요. 레코드의 요구 정렬은 다음과 같이 계산돼요.
- 요구 정렬은 레이아웃을 잡는 동안 결정된, 가장 큰 정렬을 가진 레코드 필드의 정렬로 설정돼요.
- 현재
{$ALIGN N}또는{$PACKRECORDS N}설정이 C가 아니고, 요구 정렬이 현재 활성화된{$CODEALIGN RECORDMAX=X}보다 크면, 요구 정렬은 X로 바뀌어요. - 현재
{$ALIGN N}또는{$PACKRECORDS N}설정이 C와 같으면, 요구 정렬은 공식 ABI 규칙에 따라 결정돼요.
Remarks와 예제
Free Pascal은 "packed record"도 지원하는데, 모든 요소가 바이트 정렬된 레코드예요. 결과적으로 아래 두 선언은 동일해요.
{$PackRecords 1}
Trec2 = Record
A : Byte;
B : Word;
end;
{$PackRecords default}
그리고
Trec2 = Packed Record
A : Byte;
B : Word;
end;
첫 번째 선언 뒤의 {$PackRecords Default}로 기본 설정을 복원한다는 점에 주의하세요!
레코드가 메모리에 배치되는 방식은 플랫폼에 의존적이므로, 플랫폼 간에 호환되는 레이아웃을 보장하는 유일한 방법은 {$PACKRECORDS 1}을 쓰는 것이에요. (모든 필드가 이 플랫폼들에서 같은 의미의 타입으로 선언됐다고 가정할 때요.)
특히 Turbo Pascal 프로그램이 만든 레코드가 담긴 타입 파일을 읽어야 한다면, 제대로 읽는 게 사실상 실패할 가능성이 높아요. Free Pascal의 기본 {$PACKRECORDS N} 설정이 Turbo Pascal과 반드시 호환되지는 않기 때문이죠. 파일을 만든 Turbo Pascal 프로그램에서 쓴 설정에 따라 {$PACKRECORDS 1}이나 {$PACKRECORDS 2}로 바꿀 수 있어요. (16비트 MSDOS와 현재 플랫폼의 타입 정렬 요구사항이 달라 {$PACKRECORDS 2}에서도 실패할 수 있어요.)
Delphi에도 같은 이야기가 적용돼요. 데이터 교환이 보장되려면 생산자와 소비자가 모두 packed record를 쓰거나, 같은 플랫폼에서 같은 {$PACKRECORDS X} 설정을 써야 해요.
더 알아보기
레코드 레이아웃을 다룰 때는 정렬 설정({$ALIGN}/{$PACKRECORDS})을 신경 써야 해요. 외부 데이터 파일이나 다른 언어와 교환할 때는 {$PACKRECORDS 1}을 고려하세요.