Gosu.Net 아티클 퍼옵@


Low-Level 키보드 입력 후킹의 이해를 돕기 위한 아티클입니다. unsafe 키워드를 사용해야 할 일이 그렇게 많지는 않겠지만, WinAPI를 다뤄야 한다면 피해갈 수 없는 부분이므로, 아직 C#에 그렇게까지 익숙하지는 않지만 한번 소개해 보겠습니다 : )



우리는 포인터가 필요하다


Kenial은 처음으로 c/c++을 공부하는 사람이 가장 이해하기 어려운 부분이 포인터가 아닐까. 라고 생각한다. 시스템에 접근할 수 있는 가장 저수준의 도구이면서, '기계의 입장에서' 생각하지 않으면 도저히 이해할 수 없는 부분이 아닐까.


사실 포인터 없이도 좋은 프로그램을 만들 수는 있다. 하지만 우리는 아직도 WinAPI를 벗어날 수 없고, WinAPI와 상호작용할 수 있는 코드를 만들고 싶다면, 포인터는 필요하다. 물론 포인터 없이도 가능한 일이기는 하지만, 그만큼 코드가 늘어난다거나 지저분한 코드를 얻게 되는 등의 댓가를 치뤄야 하므로...



unsafe 키워드


msdn의 c# programmer's reference를 참고하면, unsafe를 이렇게 설명하고 있다 :


    The unsafe keyword denotes an unsafe context, which is required for any operation involving pointers.


말 그대로, unsafe한 내용을 표시할 때 사용되는 키워드이다. 일단 간단한 다음 코드를 보자 :


int a;

int *b = &a;    


a를 참조하는 포인터 변수 b를 선언하는 코드이다. c#에서 &과 *이 횡행하는 코드를 봐서 당황스러울 수는 있겠으나, 막상 컴파일을 해 보면 문법 에러는 발생하지 않는다. 다음과 같은 에러가 발생할 것이다 : 포인터는 안전하지 않은 컨텍스트 안에서만 사용할 수 있습니다.


여기서 말하는 '안전하지 않은 컨텍스트'를 표시하는 기능을 가진 키워드가 바로 unsafe인 것이다. 다음과 같이 코드를 고치고 다시 컴파일 해 보도록 하자 :


unsafe {

    int a;

    int *b = &a;    

}


잘 컴파일되는가? 천만의 말씀이다. 이번에는 이런 에러가 발생할 것이다 : 안전하지 않은 코드는 /unsafe를 사용하여 컴파일하는 경우에만 나타날 수 있습니다.


기본적으로 마이크로소프트에서는 '안전하지 않은 코드'를 사용하는 것을 무척이나 싫어하는게 아닐까 하는 생각이 든다. (물론 당연한 생각이긴 하지만..) unsafe 키워드를 사용한 프로그램은 컴파일러에서 /unsafe 옵션을 주어야 하며, 이는 프로젝트 속성을 바꿔주면 된다.


'안전하지 않은 코드 블록 허용' 항목을 true로 세팅한다.


이와 같이 설정을 바꾸면 코드가 제대로 컴파일되는 것을 확인할 수 있을 것이다.



unsafe 선언의 다른 형태


짐작했겠지만, unsafe는 위와 같이 코드 블록에만 사용할 수 있는 것은 아니다.


unsafe private void ThisIsUnsafeFunction( void* pvVoid )

{

    ...

}

unsafe class UnsafeClass

{

        //...

}

unsafe delegate void* UnsafeEventHandler ( int* i );

unsafe event UnsafeEventHandler UnsafeEvent;


보시다시피, 함수나 클래스, 딜리게이트, 이벤트까지 사용 가능하다. 딜리게이트의 경우, 이벤트 핸들러의 파라메터나 리턴 값이 포인터일 경우에 unsafe 키워드를 사용해야 한다.


event의 경우 unsafe를 선언할 수는 있지만, 어떤 경우에 사용해야 하는지는 Kenial도 아직 모른다. 혹시 아는 분은 부디 Kenial에게 깨우침을 주시길...



정리


포인터를 사용하기 위한 키워드인 unsafe에 대하여 간단히 알아보았습니다. 하지만 예전 c/c++ 처럼 포인터를 사용해서 객체를 전달하는 것 같은 일을 간단하게 수행할 수는 없고, 여러가지 제약이 있습니다. 물론 이것도 피해가는 방법이 있습니다만, 일단은 천천히 소개하기로 하죠.

AND