멤버 함수 포인터의 크기

C 에서 함수포인터의 크기는 아주 예외적인 경우를 제외하고는 void* 의 크기와 같다. 즉, 모든 포인터의 크기가 CPU word 크기다1 하지만 멤버 함수 포인터의 경우는 조금 다른 얘기가 된다.

지지난 주에 우연히 발견하게 된 사실인데 — Visual Studio 2005의 데이터 visualization 버그인듯 함 — 멤버 함수 포인터를 저장하고, 이걸 가지고 모종의 작업을 하는 템플릿 라이브러리를 짰는데 — 2년 전에 작성해놓고 그 동안 잘 쓰던 녀석 — 이 녀석을 쓰는 코드를 디버깅하다가 생각없이 실행 스택을 따라 내려갔는데, 멤버 함수 포인터 배열에 3단위(12  bytes)로 뛰어넘으면서 접근하는게 아닌가!

실제로는 다른 부분의 코드에서도 일관성 있게 접근하고, 이걸 template 없이 짜면 별 이상없이 1 단위로 점프하는걸로 봐선(여기선 그냥 8bytes씩) 그냥 버그인듯.2 Visual Studio 와 관련해서는 Raymond Chen이  이걸 잘 정리해놨다 — Pointers to member functions are very strange animals. 즉, member function pointer 그 자체와, data 영역에 대한 오프셋이 들어가서 저 모양이란 소리.

GCC 에 대해서도 간단한 코드를 돌려보니 비슷한 결과가 나온다.  Mac OS X(Snow Leopard) 에서 4개의 (일반) 함수포인터를 넣은 배열의 크기 32 bytes, 멤버 함수 포인터를 4개 넣은 경우엔 64 bytes 크기로 나왔다. 즉, 각각 8 bytes 와 16 bytes. 윈도우즈의 예랑 좀 다른건 이 경우엔 64bit 으로 컴파일 했기 때문. 32  bit linux에서 동일한 파일을 컴파일해서 실행해보면 16  bytes / 32 bytes 가 나올 뿐…

결론: Compiler 마다 멤버 함수 포인터 크기는 다를 수 있으며, 이 역시 플랫폼(CPU 워드 크기 / OS / 컴파일러)에 따라 다르게 된다. 그리고 일반적으로 이 크기는 일반 함수 포인터 보다 크다. 왜냐하면 다중 상속이나 virtual 상속이 있을 수 있어서.


  1. MS Windows 환경에 익숙한 사람들이라면 WORD 타입이랑 헷갈릴지도 모르지만, 이건 OS 관점에서의 형 문제로, 이 글에서 언급하는 word 크기는 해당 플랫폼이 생각하는 CPU 레지스터 크기다. ↩︎

  2. 그러니까 IDE에서 데이터를 보여주는 부분의 아주 미묘한/사소한 버그. ↩︎