티스토리 뷰
목차
파이썬 CTypes 구조체 자세히 알아보기 (PyThon, 파이선)
파이썬에서 외부 라이브러리를 쓰기 위해서는 확장 모듈을 만들고 그 속에서 외부 라이브러리를 호출하는 방법이 있습니다. 사실 이보다 훨씬 더 간단한 방법이 있었는데, 바로 파이선에서 제공하는 파이썬 ctypes 모듈을 사용하는 것입니다. ctypes 모듈을 이용하면 C의 데이터 타입이나, DLL 혹은 공유 라이브러리(shared library)의 함수를 직접 사용할 수 있습니다.
[Python 자료형] 확장 모듈과 라이브러리
파이선 ctypes를 사용하는 방법은 매우 간단합니다. 다음 예제를 보겠습니다.
1 2 3 4 5 6 | >>> import ctypes <- 윈도우에서 테스트 한 결과. >>> print(ctypes.windll.kernel32) <WinDLL 'kernel32', handle ... at ...> >>> print(ctypes.cdll.msvcrt) <CDLL 'msvcrt', handle ... at ...> | cs |
파이썬 ctypes를 임포트하는 것으로 모든 준비가 끝납니다.
위 예제에서는 'stdcall' 방식의 함수는 windll로, 'cdecl' 방식의 함수는 cdll을 통해 호출하는 것을 보여줍니다. 이제는 직접 윈도우에 들어 있는 kernel32.dll 안의 함수를 호출해 보겠습니다.
1 2 | >>> print(hex(ctypes.windll.kernel32.GetModuleHandleA(None))) 0x1d000000 | cs |
참조 사항
stdcall와 cdecl은 함수 호출 규약이며, 함수가 호출될 때 매개변수가 스택에서 어떻게 전달되는지에 따라 stdcall과 cdecl로 나눌 수 있습니다.
stdcall은 불려진 함수가 스택에서 인자를 꺼내는(pop) 것이고, cdecl은 호출한 함수에서 스택의 인자를 꺼냅니다.
[Python 자료형] 확장 모듈과 라이브러리
파이썬 ctypes는 외부 함수 호출 말고도 C의 데이터 타입을 쓸 수가 있습니다. 아래는 기본적인 ctypes 함수가 지원하는 타입니다.
ctypes 타입 |
C 타입 |
Python 타입 |
c_short |
Short |
int |
c_ushort |
unsigned short |
int |
c_int |
Int |
int |
c_uint |
unsigned int |
int |
c_long |
Long |
int |
c_ulong |
usigned long |
int |
c_longlong |
__int64 혹은 long long |
int |
c_ulonglong |
unsigned __int64 혹은 unsigned long long |
int |
c_float |
Float |
float |
c_double |
Double |
float |
c_longdouble |
long double |
float |
c_char_p |
char * (NULL terminated) |
unicode 혹은 None |
c_wchar_p |
wchar_t * (NULL terminated) |
unicode 혹은 None |
이를 이용해 간단한 예제를 만들겠습니다.
1 2 3 4 5 | >>> from ctypes import * >>> i = c_int(10) >>> print("ctypes : ", i ,", value : ", i.value ) ctypes : c_long(10), value : 10 | cs |
또한 다음 예제와 같이 파이썬 ctypes는 포인터도 지원합니다.
1 2 3 4 | >>> k = c_int(10) >>> pk = pointer(k) <- c_int(10)의 포인터 값을 가져옵니다. >>> print("position :", pointer(k), ", contents :", pk.contents) position : <__main__.LP_c_long object at 0x018931C0> , contents : c__long(10) | cs |
게다가 구조체와 유니온(union)은 다음과 같이 표현할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 | >>> import ctypes >>> class POINT(ctypes.Structure): _fields_ = [("X", ctypes.c_int), ("y", ctypes.c_int)] >>> point = POINT(10, 20) >>> print(point.x, point.y) 10 20 >>> point = POINT(y=5) >>> print(point.x, point.y) 0 5 |
구조체와 유니온은 파이선에서 class로 표현되기 때문에 일단 class 객체를 생성하고, _fields_ 멤버 변수를 이용해 각 멤버 변수를 설정해주는 것입니다.
[Python 자료형] 확장 모듈과 라이브러리
다음 예제에서는 실제로 파이썬 ctypes을 어떻게 사용하는지 보겠습니다. 우선 윈도우에는 사용자에게 메시지 박스를 보여주는 MessageBoxA()라는 함수가 정의돼 있습니다. winuser.h 헤더파일에 정의돼 있는 MessageBoxA는 다음과 같습니다.
1 2 3 4 5 6 | WINUSERAPI int WINAPI MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType); | cs |
ctypes 모듈을 이용해 이를 래핑(wrapping)해 보겠습니다.
1 2 3 4 5 | >>> from ctypes import c_int, WINFUNCTYPE, windll >>> from ctypes.wintypes import HWND, LPCSTR, UINT >>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT) >>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0) >>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags) | cs |
이제 Python에서 MessageBox는 윈도우의 MessageBoxA() 함수를 가리킵니다. MessageBox를 아래와 같이 호출해 보겠습니다.
1 2 | >>> MessageBox(text="Please, programming with python") >>> MessageBox(text="Do you know about python?", flags=3) | cs |
그리하면 윈도우의 메시지 창이 나타나는 것을 볼 수 있습니다.
파이썬 CTypes 구조체 자세히 알아보기 (PyThon, 파이선)