본문 바로가기
C++ 200제/코딩 IT 정보

파이썬 CTypes 구조체 자세히 알아보기 (PyThon, 파이선)

by vicddory 2018. 2. 23.

파이썬 CTypes 구조체 자세히 알아보기 (PyThon, 파이선)


파이썬에서 외부 라이브러리를 쓰기 위해서는 확장 모듈을 만들고 그 속에서 외부 라이브러리를 호출하는 방법이 있습니다. 사실 이보다 훨씬 더 간단한 방법이 있었는데, 바로 파이선에서 제공하는 파이썬 ctypes 모듈을 사용하는 것입니다. ctypes 모듈을 이용하면 C의 데이터 타입이나, DLL 혹은 공유 라이브러리(shared library)의 함수를 직접 사용할 수 있습니다.


파이썬 ctypes 구조체 파이선[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은 호출한 함수에서 스택의 인자를 꺼냅니다.


ctypes 파이썬 구조체[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(1020)
>>> print(point.x, point.y)
10 20
 
>>> point = POINT(y=5)
>>> print(point.x, point.y)
0 5

cs


구조체와 유니온은 파이선에서 class로 표현되기 때문에 일단 class 객체를 생성하고, _fields_ 멤버 변수를 이용해 각 멤버 변수를 설정해주는 것입니다.


파이썬 CTypes 구조체 자세히 알아보기 (PyThon, 파이선)[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, 파이선)

댓글