티스토리 뷰

Development/C#

C#의 알려지지 않은 비공식 키워드들

알 수 없는 사용자 2008. 7. 8. 19:38
반응형
우연히 printf 계열의 함수들에 대한 플랫폼 호출 방법에 대한 자료를 찾는 도중 재미있는 글을 발견하였습니다. C#의 공식 사양에 포함되지 않은 Microsoft C# 컴파일러의 특수한 기능들 (Mono나 DotGNU의 C# 컴파일러에는 존재하지 않거나 의도하지 않은 예외가 발생할 수도 있습니다.)을 알게 되었습니다.

주의: 비공식 키워드를 사용하는 것에 대한 책임은 프로그래머에게 달려있습니다. 다른 언어들과의 호환성 문제와 부딪히지 않으려면 이러한 비공식 키워드의 사용에 주의해야만 합니다.

TypedReference에 대한 비공식 키워드

TypedReference 형식은 관리되는 객체에 대한 명확한 주소 정보 및 핸들 정보를 가리키는 특수한 객체입니다. TypedReference 형식의 객체를 만들기 위한 비공식 키워드가 C#에 존재합니다.

__makeref(변수) : 괄호 안에 TypedReference 형식으로 조사하기를 원하는 객체를 지정하면 되는데, 여기에는 값 형식의 변수가 올 수도 있습니다. 예를 들면 다음과 같습니다.

int x = 0;
TypedReference xt = __makeref(x);

__reftype(TypedReference 객체) : 괄호 안에 TypedReference 객체를 지정하면 TypedReference 객체가 원래 가리키고 있던 객체의 형식 정보를 반환합니다. 예를 들어, 위의 예에서 System.Int32에 대한 TypedReference를 만들었는데 이 키워드를 사용함으로서 System.Int32에 대한 Type 객체가 반환됩니다.

int x = 0;
TypedReference xt = __makeref(x);
Type xt2 = __reftype(xt);

__refvalue(TypedReference 객체, 가져오기 원하는 형식) : 괄호 안에 TypedReference 객체를 첫 인수로 지정하고, TypedReference가 가리키고 있는 실제 객체에 대한 형식명을 두 번째 인수로 지정합니다. 이 키워드를 이용하여 TypedReference 객체로부터 곧바로 원래의 객체를 가져올 수 있습니다.

int x = 0;
TypedReference xt = __makeref(x);
Type xt2 = __reftype(xt);
int y = __refvalue(xt, int);

printf, sprintf, fprintf와 같이 C 언어에서만 사용하는 가변 인수를 C#에서도 도입하기

va_args, va_start, va_end와 같은 매크로 함수를 혹시 기억하십니까? printf 같이 인수를 가변적으로 조절할 수 있는 함수를 디자인하기 위하여 사용했던 함수들입니다. 이러한 함수들을 흉내내기 위하여 C#에서는 params 키워드를 제공하였고 그 결과 가변 인수처럼 동작하면서도 결과적으로 1차원 배열을 다룰 수 있는 향상된 가변 인수 처리법을 제공할 수 있게 되었습니다. 하지만 이렇게 변경된 가변 인수 처리법은 종전의 C 언어 스타일과는 크게 다르기 때문에 C 언어를 위하여 디자인된 printf 계의 함수들은 사용할 수 없는 것 처럼 이야기되어왔습니다. 하지만 지금 소개하는 __arglist 키워드를 이용함으로서 이런 한계를 극복할 수 있습니다.

[SecurityPermission(SecurityAction.LinkDemand)]
[DllImport(ModuleName, CharSet = CharSet.Ansi)]
protected static extern int _cprintf(string fmt, __arglist);

__arglist라는 키워드를 주목합니다. 매개 변수 형식 선언이 아님에도 불구하고 사용할 수 있다는 것이 매우 특이한데, 바로 이것이 C 언어 스타일의 가변 인수여야 함을 컴파일러에게 알려주는 힌트가 됩니다. 하지만 이렇게 선언하면 뒷쪽에 가변 인수를 제공하기 위하여 __arglist() 키워드를 사용하여야 하지만, __arglist라는 키워드를 지원하지 못하는 다른 프로그래밍 언어에서는 사용할 수 없습니다.

이제 위의 _cprintf 함수를 부르는 예제를 보기로 합니다.

int result = _cprintf("%d", __arglist(30));

그렇습니다. __arglist라는 가상의 매크로에 필요한 만큼 인수를 던져주면 됩니다. 그러면, 여기서 궁금한 점이 하나 더 생기는데 __arglist를 params 키워드 대신해서 사용할 수도 있을까에 대한 의문입니다. 그 답은 "Yes"입니다. 다음의 코드를 보겠습니다.

protected void Page_Load(Object sender, EventArgs e)
{
   int x=85;
   string y = "a stringy thingy";
   double d=19.45;
   WriteToPage(__arglist(x,y,d));
}

public  void WriteToPage(__arglist)
{
   ArgIterator ai = new ArgIterator(__arglist);
   while(ai.GetRemainingCount() >0)
   {
      TypedReference tr = ai.GetNextArg();
      Response.Write(TypedReference.ToObject(tr)+"<BR>");
   }
}

int, string, double 형의 변수를 선언하고 __arglist(x,y,d)로 이들 인수를 던집니다. 그러면 WriteToPage 메서드에서는 이렇게 받아들인 인수들을 조회하기 위하여 ArgIterator 객체를 사용하여 하나씩 조회합니다. ArgIterator 객체로 조회한 매개 변수들은 TypedReference로 포장된 객체들이므로 실제 객체를 위의 코드처럼 TypedReference.ToObject 메서드로 가져오거나 __refvalue 키워드를 이용하여 가져와서 사용하는 것입니다.
출처 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=18&MAEULNO=8&no=1497&page=1 
(남정현님의 팁 & 강좌)
반응형
댓글