Array of Const
Array of Const (가변 인자)
가변 개수의 인자를 함수에 넘기고 싶을 때가 있어요. Object Pascal이나 Delphi 모드의 Free Pascal은 Array of Const 구조를 지원해서, 함수나 프로시저에 임의의 표현식들을 배열로 넘길 수 있게 해줘요.
본문
Object Pascal 또는 Delphi 모드에서 Free Pascal은 서브루틴에 매개변수를 전달하기 위한 Array of Const 구조를 지원해요.
이것은 개방 배열(open array) 구성의 특별한 경우예요. 개방 배열에서는 배열의 어떤 요소든 함수나 프로시저에 전달하는 것이 허용돼요. 이때 표현식은 단순한 결과 타입을 가져야 해요. 구조체는 인자로 전달될 수 없어요. 즉 모든 ordinal, float, string 타입뿐만 아니라 포인터, 클래스, 인터페이스도 전달될 수 있어요(후자의 둘은 실제로 포인터이기 때문이에요).
Array of Const의 요소들은 특별한 variant 레코드로 변환돼요.
Type
PVarRec = ^TVarRec;
TVarRec = record
case VType : Ptrint of
vtInteger : (VInteger: Longint);
vtBoolean : (VBoolean: Boolean);
vtChar : (VChar: Char);
vtWideChar : (VWideChar: WideChar);
vtExtended : (VExtended: PExtended);
vtString : (VString: PShortString);
vtPointer : (VPointer: Pointer);
vtPChar : (VPChar: PChar);
vtObject : (VObject: TObject);
vtClass : (VClass: TClass);
vtPWideChar : (VPWideChar: PWideChar);
vtAnsiString : (VAnsiString: Pointer);
vtCurrency : (VCurrency: PCurrency);
vtVariant : (VVariant: PVariant);
vtInterface : (VInterface: Pointer);
vtWideString : (VWideString: Pointer);
vtInt64 : (VInt64: PInt64);
vtQWord : (VQWord: PQWord);
end;
따라서 프로시저 본문 안에서, Array of Const 인자는 TVarRec의 개방 배열과 동등해요.
Procedure Testit (Args: Array of const);
Var I : longint;
begin
If High(Args)<0 then
begin
Writeln ('No aguments');
exit;
end;
Writeln ('Got ',High(Args)+1,' arguments :');
For i:=0 to High(Args) do
begin
write ('Argument ',i,' has type ');
case Args[i].vtype of
vtinteger :
Writeln ('Integer, Value :',args[i].vinteger);
vtboolean :
Writeln ('Boolean, Value :',args[i].vboolean);
vtchar :
Writeln ('Char, value : ',args[i].vchar);
vtextended :
Writeln ('Extended, value : ',args[i].VExtended^);
vtString :
Writeln ('ShortString, value :',args[i].VString^);
vtPointer :
Writeln ('Pointer, value : ',Longint(Args[i].VPointer));
vtPChar :
Writeln ('PChar, value : ',Args[i].VPChar);
vtObject :
Writeln ('Object, name : ',Args[i].VObject.Classname);
vtClass :
Writeln ('Class reference, name :',Args[i].VClass.Classname);
vtAnsiString :
Writeln ('AnsiString, value :',AnsiString(Args[I].VAnsiString);
else
Writeln ('(Unknown) : ',args[i].vtype);
end;
end;
end;
코드에서는 이 프로시저에 임의의 요소 배열을 전달할 수 있어요.
S:='Ansistring 1';
T:='AnsiString 2';
Testit ([]);
Testit ([1,2]);
Testit (['A','B']);
Testit ([TRUE,FALSE,TRUE]);
Testit (['String','Another string']);
Testit ([S,T]) ;
Testit ([P1,P2]);
Testit ([@testit,Nil]);
Testit ([ObjA,ObjB]);
Testit ([1.234,1.234]);
TestIt ([AClass]);
만약 프로시저가 cdecl 수정자로 선언되면, 컴파일러는 배열을 C 컴파일러가 전달하는 방식으로 전달해요. 이것은 사실상 C의 가변 인자(varargs) 구성을 흉내 내는 것이에요. 다음 예시를 보면 알 수 있어요.
program testaocc;
{$mode objfpc}
Const
P : PChar = 'example';
Fmt : PChar =
'This %s uses printf to print numbers (%d) and strings.'#10;
// Declaration of standard C function printf:
procedure printf (fm : pchar; args : array of const);cdecl; external 'c';
begin
printf(Fmt,[P,123]);
end.
참고: 이 동작은 Delphi에서는 사실이 아니에요. 이 기능에 의존하는 코드는 이식되지 않을 수 있어요.
참고: Array of Const에는 DWord(또는 cardinal) 인자에 대한 지원이 없어요. 그것들은 vtInteger/vtLongint로 변환돼요. 이것은 Delphi 호환을 위한 것이고, Delphi 모드에서는 컴파일러가 그로 인한 범위 검사를 무시해요.
더 알아보기
- 개방 배열 매개변수의 기본 개념은 14.4.5에서 다뤄요.
- C 언어의 가변 인자(varargs)와 비교해서 보면 구조를 이해하기 쉬워요.