서수 타입

서수 타입 (Ordinal types)

Pascal에서 타입을 이해하는 첫걸음은 '셀 수 있는 타입'인 서수 타입(ordinal type)이에요. 정수 계열, 열거형, 부분범위 타입이 모두 여기에 속하고, 이들을 다루는 함수들이 일관되게 동작하는 이유도 여기서 나와요.

출처: Free Pascal Reference — Ordinal types

본문

부동소수점 값 타입을 제외한 모든 기본 타입은 서수 타입이에요. 서수 타입은 다음 특징을 가져요.

  • 서수 타입은 셀 수 있고(countable) 순서가 있어요(ordered). 즉 지정된 순서대로 하나씩 세어 나가는 것이 원칙적으로 가능해요. 이 속성 덕분에 Inc, Ord, Dec 같은 함수를 서수 타입에 적용하는 것이 정의될 수 있어요.
  • 서수 값에는 최솟값이 있어요. 범위 검사(range checking)가 켜져 있는 상태에서 최솟값에 Pred 함수를 적용하면 범위 검사 오류가 발생해요.
  • 서수 값에는 최댓값도 있어요. 범위 검사가 켜져 있으면 최댓값에 Succ 함수를 적용할 때 범위 검사 오류가 발생해요.

참고 Int64QWord는 64비트 CPU에서는 서수 타입으로 간주돼요. 32비트 타입에서는 서수의 특징 일부를 갖지만 for 루프 같은 데에는 쓸 수 없어요.

정수 (Integers)

미리 정의된 정수 타입의 목록은 표 3.1에 제시돼 있어요.

표 3.1: 미리 정의된 정수 타입

Integer, Shortint, SmallInt, Longint, Longword, Int64, Byte, Word, Cardinal, QWord, ByteBool, WordBool, LongBool, QWordBool

Free Pascal에 미리 정의된 정수 타입과 그 범위·크기는 표 3.2에 나열돼 있어요. qwordint64 타입은 진짜 서수(ordinal)가 아니므로 일부 Pascal 구문이 이 두 정수 타입에서는 동작하지 않는다는 점에 주의하세요.

표 3.2: 미리 정의된 정수 타입

Type Range Size in bytes
Byte 0 .. 255 1
Shortint -128 .. 127 1
Smallint -32768 .. 32767 2
Word 0 .. 65535 2
Integer either smallint or longint size 2 or 4
Cardinal longword 4
Longint -2147483648 .. 2147483647 4
Longword 0 .. 4294967295 4
Int64 -9223372036854775808 .. 9223372036854775807 8
QWord 0 .. 18446744073709551615 8

integer 타입은 기본 Free Pascal 모드에서는 smallint 타입의 별칭(alias)이고, Delphi 또는 ObjFPC 모드에서는 longint 타입의 별칭이에요. cardinal 타입은 현재 항상 longword 타입으로 매핑돼요.

참고 컴파일러는 정수 상수의 타입을 그 값에 따라 결정해요. 정수 상수는 가능한 가장 작은 부호 있는(signed) 타입을 갖게 되며, 표 3.3의 첫 번째 매칭이 사용돼요.

표 3.3: 정수 상수 타입 매핑

Range Type
-128..127 Shortint
128..255 Byte
-32768..32767 Smallint
32768..65535 Word
-2147483648..2147483647 longint
2147483648..4294967295 Cardinal (longword)
-9223372036854775808 .. 9223372036854775807 Int64

즉 -128..127 범위의 상수는 shortint로, 128..255 범위는 byte로 매핑돼요. 2147483647..high(cardinal) 범위의 상수는 cardinal로 해석되고, 위 어느 범위에도 맞지 않는 10진 상수는 64비트 정수 상수로 해석돼요.

참고 최신 Delphi 버전에서 longint 타입은 플랫폼과 CPU에 따라 달라져요. 그러나 FPC에서는 longint가 모든 플랫폼에서 32비트로 고정되어 있어요.

서로 다른 종류의 정수 타입이 섞인 식에서 Free Pascal은 자동 타입 변환과 승격(upgrading)을 수행해요. 모든 플랫폼은 8비트, 16비트, 32비트, 64비트 여부에 따라 네이티브 정수 크기를 가져요(예: AVR은 8비트). 네이티브 크기보다 작은 모든 정수는 네이티브 크기의 부호 있는 버전으로 승격돼요. 네이티브 크기와 같은 정수는 부호성을 유지해요.

이진 산술 연산자(+, -, * 등)의 결과는 다음과 같이 결정돼요. 피연산자 중 하나라도 네이티브 정수 크기보다 크면, 결과는 두 피연산자 타입의 범위를 모두 포함하는 가장 작은 타입으로 선택돼요. 즉 부호 없는 타입과 그보다 작거나 같은 크기의 부호 있는 타입을 섞으면 둘 다보다 큰 부호 있는 타입이 나와요. 두 피연산자의 부호성이 같으면 결과도 같은 타입이에요.

유일한 예외는 뺄셈(-)이에요. 부호 없는 - 부호 없는 뺄셈은 FPC에서 부호 있는 결과를 만들어요(Delphi와 동일하지만 TP7과는 다름). 네이티브 정수 크기의 부호 있는·부호 없는 피연산자를 섞으면 더 큰 부호 있는 결과가 나와요. 즉 32비트 플랫폼에서 longintlongword를 섞으면 int64가 생겨요. 마찬가지로 8비트 플랫폼(AVR)에서 byteshortint를 섞으면 smallint가 생겨요.

불리언 타입 (Boolean types)

Free Pascal은 두 개의 미리 정의된 값 TrueFalse를 가진 Boolean 타입을 지원해요. 이 두 값만 Boolean 타입에 할당할 수 있어요. 물론 불리언 값으로 평가되는 어떤 표현식도 불리언 타입에 할당할 수 있어요.

표 3.4: 불리언 타입

Name Size Ord(True)
Boolean 1 1
Boolean16 2 1
Boolean32 4 1
Boolean64 8 1
ByteBool 1 Any nonzero value
WordBool 2 Any nonzero value
LongBool 4 Any nonzero value
QWordBool 8 Any nonzero value

단순 Boolean 타입 외에도 Boolean16, Boolean32, Boolean64 타입이 있어요. 이것들은 사실 정수 타입이며, 단순 불리언 타입과 할당 호환(assignment-compatible)이에요. 정수로서 TrueFalse의 값은 각각 1과 0이에요. 이는 0과 1 값을 갖는 이 크기의 불리언을 정의한 C 코드와 인터페이스할 때 사용할 수 있어요.

C와의 인터페이스를 더 쉽게 하기 위해 Free Pascal은 ByteBool, WordBool, LongBool, QWordBool 타입도 지원해요. 이들은 Byte, Word, Longint 또는 Int64 타입이지만 다시 Boolean과 할당 호환이에요. Boolean16/32/64 타입과의 유일한 차이는 무엇을 true/false로 보느냐예요. False 값은 0(영)과 동등하고, 불리언 값으로 변환할 때 0이 아닌 값은 모두 True로 간주돼요. True 불리언 값이 ByteBool, WordBool, LongBool 또는 QWordBool 타입의 변수에 할당되면 Not(0)으로 변환돼요.

BBoolean 타입이라고 가정하면 다음은 유효한 할당이에요.

B := True;
 B := False;
 B := 1<>2;  { Results in B := True }

불리언 표현식은 조건문에서도 사용돼요.

참고 Free Pascal에서 불리언 표현식은 기본적으로 결과가 알려지면 나머지 표현식을 더 이상 평가하지 않는 방식으로 항상 평가돼요. 이를 short-cut boolean evaluation이라고 해요.

다음 예에서 함수 Func는 절대 호출되지 않으며, 이는 이상한 부작용을 일으킬 수 있어요. 여기서 FuncBoolean 타입을 반환하는 함수예요.

...
 B := False;
 A := B and Func;

이 동작은 {$B } 컴파일러 지시어로 제어할 수 있어요.

열거 타입 (Enumeration types)

Free Pascal은 열거 타입을 지원해요. Turbo Pascal 구현에 더해, Free Pascal은 열거 목록의 특정 요소에 값을 할당하는 C 스타일의 열거 확장도 허용해요.

Type
  Direction = ( North, East, South, West );

값이 할당된 열거 타입을 사용할 때는 할당된 요소가 목록에서 오름차순이어야 해요. 그렇지 않으면 컴파일러가 오류를 냅니다. (식을 어떻게 쓰는지는 12장, 583페이지 참고) 할당된 열거 요소에 사용된 식은 컴파일 타임에 알려져야 해요. 따라서 다음은 올바른 열거 타입 선언이에요.

Type
  EnumType = (one, two, three, forty := 40,fortyone);

C 스타일 열거 타입은 다음과 같이 생겼어요.

Type
  EnumType = (one, two, three, forty = 40,fortyone);

또는 다음과 같이 쓸 수도 있어요. 후자(=) 표기는 DELPHI 모드에서 필수예요.

그 결과 forty의 서수 번호는 := 40이 없었을 때의 3이 아니라 40이 돼요. fortyone의 서수 값은 할당이 없었을 때의 4가 아니라 41이 돼요. 열거 정의에서 할당 뒤에는 컴파일러가 다음 열거 값에 할당된 값 + 1을 부여해요.

이런 열거 타입을 지정할 때는 열거 요소를 오름차순으로 유지하는 것이 중요해요. 다음은 컴파일러 오류를 만들어요.

Type
  EnumType = (one, two, three, forty := 40, thirty := 30);

fortythirty의 순서를 올바르게 유지해야 해요. 열거 타입을 사용할 때는 다음 사항을 기억하세요.

  • PredSucc 함수는 이런 종류의 열거 타입에는 사용할 수 없어요. 그렇게 하면 컴파일러 오류가 나요.
  • 열거 타입은 실제 값의 개수와 무관하게 기본 방식으로 저장돼요. 즉 컴파일러는 공간을 최적화하지 않아요. 이 동작은 {$PACKENUM n} 컴파일러 지시어로 바꿀 수 있는데, 이 지시어는 열거 타입에 사용할 최소 바이트 수를 알려줘요.

예를 들어

Type
{$PACKENUM 4}
  LargeEnum = ( BigOne, BigTwo, BigThree );
{$PACKENUM 1}
  SmallEnum = ( one, two, three );
Var S : SmallEnum;
    L : LargeEnum;
begin
  WriteLn ('Small enum : ',SizeOf(S));
  WriteLn ('Large enum : ',SizeOf(L));
end.

를 실행하면 다음을 출력해요.

Small enum : 1
Large enum : 4

더 자세한 정보는 Programmers Guide의 컴파일러 지시어 섹션에서 찾을 수 있어요.

부분범위 타입 (Subrange types)

부분범위 타입은 서수 타입(호스트 타입)에서 나온 값의 범위예요. 부분범위 타입을 정의하려면 한계 값, 즉 타입의 최고값과 최저값을 지정해야 해요.

미리 정의된 정수 타입 중 일부는 부분범위 타입으로 정의돼 있어요.

Type
  Longint  = $80000000..$7fffffff;
  Integer  = -32768..32767;
  shortint = -128..127;
  byte     = 0..255;
  Word     = 0..65535;

열거 타입의 부분범위 타입도 정의할 수 있어요.

Type
  Days = (monday,tuesday,wednesday,thursday,friday,
          saturday,sunday);
  WorkDays = monday .. friday;
  WeekEnd = Saturday .. Sunday;

문자 타입 (Character types)

문자 타입도 서수 타입이에요. 문자는 순서가 있고 셀 수 있거든요. 문자 타입은 두 가지가 있어요.

  • AnsiChar: 1바이트 문자예요. 문자의 해석은 코드 페이지(codepage)에 따라 달라져요.
  • WideChar: 2바이트 문자예요. 문자의 해석은 코드 페이지에 따라 달라져요.

문자는 루프에서 사용할 수 있고, prevsucc, 그리고 ord를 적용할 수 있어요. 문자에 대한 자세한 내용은 3.2절, 108페이지를 참고해요.

더 알아보기

  • 실수 타입은 "Real types" 문서에서 다뤄요.
  • 문자와 문자열 타입은 "Char or AnsiChar"부터 시작하는 문자·문자열 문서들을 참고해요.