Python

ctypes — 파이썬용 외부 함수 라이브러리

소스 코드: Lib/ctypes


:mod:`!ctypes`은 파이썬용 외부 함수 라이브러리입니다. C 호환 데이터형을 제공하며, DLL 또는 공유 라이브러리에 있는 함수를 호출할 수 있게 합니다. 이 라이브러리들을 순수 파이썬으로 감싸는 데 사용할 수 있습니다.

이것은 선택적 모듈. 사용자 복사본에 누락되었다면, 배포자(즉, Python을 제공받은 주체)의 문서를 찾아보십시오. 만약 본인이 배포자라면 :ref:`optional-module-requirements`를 참조하십시오.

경고

:mod:`!ctypes`는 네이티브 라이브러리와 프로세스의 메모리에 대한 저수준 액세스를 제공하여 Python의 안전 메커니즘을 우회하고 임의의 네이티브 코드를 실행할 수 있게 합니다. 잘못 사용하면 데이터와 객체를 손상시키고, 민감한 정보를 노출하거나, 충돌을 일으키거나, 실행 중인 프로세스를 손상시킬 수 있습니다.

ctypes 자습서

참고: 일부 코드 예제는 ctypes c_int 형을 참조합니다. sizeof(long) == sizeof(int)인 플랫폼에서, 이는 c_long의 별칭입니다. 따라서 c_int를 기대할 때 c_long가 인쇄되더라도 혼란스러워하지 않아도 됩니다 — 이것들은 실제로 같은 형입니다.

로드된 dll에서 함수에 액세스하기

함수는 dll 객체의 어트리뷰트로 액세스 됩니다:

>>> libc.printf
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.GetModuleHandleA)
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.MyOwnFunction)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "ctypes.py", line 239, in __getattr__
    func = _StdcallFuncPtr(name, self)
AttributeError: function 'MyOwnFunction' not found
>>>

kernel32user32 와 같은 win32 시스템 dll은 함수에 대해 ANSI 버전과 UNICODE 버전을 모두 내보내는 경우가 많습니다. UNICODE 버전은 이름 끝에 W 가 붙고, ANSI 버전은 이름 끝에 A 가 붙는 방식으로 내보내집니다. 주어진 모듈 이름을 위한 모듈 핸들 을 반환하는 win32 GetModuleHandle 함수는 다음과 같은 C 프로토타입을 가지고 있으며, UNICODE가 정의되었는지 여부에 따라 그 중 하나를 GetModuleHandle 로 노출하는 매크로가 사용됩니다:

/* ANSI version */
HMODULE GetModuleHandleA(LPCSTR lpModuleName);
/* UNICODE version */
HMODULE GetModuleHandleW(LPCWSTR lpModuleName);

windll는 마술적으로 이 중 하나를 선택하려고 하지 않으므로, GetModuleHandleAGetModuleHandleW를 명시적으로 지정하여 필요한 버전에 액세스해야 하고, 그런 다음 각각 바이트열이나 문자열 객체로 호출해야 합니다.

때때로, dll은 "??2@YAPAXI@Z"와 같은 유효한 파이썬 식별자가 아닌 이름으로 함수를 내보냅니다. 이때는 getattr()를 사용하여 함수를 조회해야 합니다:

>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")
<_FuncPtr object at 0x...>
>>>

윈도우에서, 일부 dll은 이름이 아니라 서수(ordinal)로 함수를 내보냅니다. 이 함수는 서수로 dll 객체를 인덱싱하여 액세스할 수 있습니다:

>>> cdll.kernel32[1]
<_FuncPtr object at 0x...>
>>> cdll.kernel32[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "ctypes.py", line 310, in __getitem__
    func = _StdcallFuncPtr(name, self)
AttributeError: function ordinal 0 not found
>>>

함수 호출하기

이 함수들은 다른 모든 파이썬 호출 가능 객체와 마찬가지로 호출할 수 있습니다. 이 예제는 인자를 받지 않고 의사 랜덤 정수를 반환하는 rand() 함수를 사용합니다.:

>>> print(libc.rand())
1804289383

윈도우에서는 GetModuleHandleA() 함수를 호출하여 win32 모듈 핸들을 얻을 수 있습니다 (단일 인자로 None``을 전달하고 ``NULL 포인터로 호출):

>>> print(hex(windll.kernel32.GetModuleHandleA(None)))
0x1d000000
>>>

cdecl 호출 규칙을 사용하여 stdcall 함수를 호출하면 ValueError가 발생하고, 그 반대도 마찬가지입니다:

>>> cdll.kernel32.GetModuleHandleA(None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with not enough arguments (4 bytes missing)
>>>

>>> windll.msvcrt.printf(b"spam")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with too many arguments (4 bytes in excess)
>>>

올바른 호출 규칙을 찾으려면 C 헤더 파일이나 호출할 함수에 대한 설명서를 살펴봐야 합니다.

윈도우에서는 :mod:`!ctypes`을 사용하여 함수가 유효하지 않은 인자 값을 가지고 호출될 때 일반 보호 오류로 인한 충돌을 방지하기 위해 win32 구조적 예외 처리를 사용합니다:

>>> windll.kernel32.GetModuleHandleA(32)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: exception: access violation reading 0x00000020
>>>

faulthandler 모듈은 잘못된 C 라이브러리 호출로 인한 세그멘테이션 결함과 같은 충돌을 디버깅하는 데 도움이 됩니다.

None, 정수, 바이트 객체 및 (유니코드) 문자열만 이러한 함수 호출의 매개변수로 직접 사용될 수 있는 네이티브 파이썬 객체입니다. None``은 C ``NULL 포인터로 전달되며, 바이트 객체와 문자열은 데이터가 포함된 메모리 블록을 가리키는 포인터(char* 또는 wchar_t*)로 전달됩니다. 파이썬 정수는 플랫폼의 기본 C int 유형으로 전달되며, 그 값은 해당 C 타입에 맞게 마스킹됩니다.

다른 매개변수 형식으로 함수를 호출하기 전에, 우리는 ctypes 데이터형에 대해 더 많이 배워야 합니다.

기본 데이터형

:mod:`!ctypes`은 여러 개의 기본 C 호환 데이터를 정의합니다:

ctypes 형

C 형

파이썬 형

_type_

c_bool

_Bool

bool

'?'

c_char

char

1바이트 bytes

'c'

c_wchar

wchar_t

1문자 str

'u'

c_byte

char

int

'b'

c_ubyte

unsigned char

int

'B'

c_short

short

int

'h'

c_ushort

unsigned short

int

'H'

c_int

int

int

'i' *

c_int8

int8_t

int

*

c_int16

int16_t

int

*

c_int32

int32_t

int

*

c_int64

int64_t

int

*

c_uint

unsigned int

int

'I' *

c_uint8

uint8_t

int

*

c_uint16

uint16_t

int

*

c_uint32

uint32_t

int

*

c_uint64

uint64_t

int

*

c_long

long

int

'l'

c_ulong

unsigned long

int

'L'

c_longlong

long long

int

'q' *

c_ulonglong

unsigned long long

int

'Q' *

c_size_t

size_t

int

*

c_ssize_t

Py_ssize_t

int

*

c_time_t

time_t

int

*

c_float

float

float

'f'

c_double

double

float

'd'

c_longdouble

long double

float

'g' *

c_char_p

char* (NUL 종료)

bytes 또는 None

'z'

c_wchar_p

wchar_t* (NUL 종료)

str 또는 None

'Z'

c_void_p

void*

int 또는 None

'P'

py_object

PyObject*

object

'O'

VARIANT_BOOL

short int

bool

'v'

또한, C와 libffi 모두에서 IEC 60559 호환 복소 산술(Annex G)이 지원되는 경우 다음 복소 타입들이 사용 가능합니다:

ctypes 형

C 형

파이썬 형

_type_

c_float_complex

float complex

complex

'Zf'

c_double_complex

double complex

complex

'Zd'

c_longdouble_complex

long double complex

complex

'Zg'

버전 3.15에서 변경: _type_ 타입을 F, DGZf, ZdZg 으로 대체되었습니다.

이 모든 형은 올바른 형과 값의 선택적 초기화자로 호출해서 만들어질 수 있습니다:

>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p(140018365411392)
>>> c_ushort(-3)
c_ushort(65533)
>>>

숫자 타입의 생성자는 입력 값을 __bool__(), __index__() (int 용), __float__() 또는 __complex__() 를 사용하여 변환합니다. 이는 c_bool 이 진리 값을 가진 모든 객체를 수락함을 의미합니다:

>>> empty_list = []
>>> c_bool(empty_list)
c_bool(False)

이러한 형은 가변이므로, 값을 나중에 변경할 수도 있습니다:

>>> i = c_int(42)
>>> print(i)
c_long(42)
>>> print(i.value)
42
>>> i.value = -99
>>> print(i.value)
-99
>>>

포인터 타입 c_char_p, c_wchar_p, 및 c_void_p 의 인스턴스에 새로운 값을 할당하면 포인터가 가리키는 메모리 위치 가 변경될 뿐, 메모리 블록의 내용물 은 변경되지 않습니다 (물론, 파이썬 문자열 객체는 불변하기 때문입니다.):

>>> s = "Hello, World"
>>> c_s = c_wchar_p(s)
>>> print(c_s)
c_wchar_p(139966785747344)
>>> print(c_s.value)
Hello World
>>> c_s.value = "Hi, there"
>>> print(c_s)              # 메모리 위치가 변경됨
c_wchar_p(139966783348904)
>>> print(c_s.value)
Hi, there
>>> print(s)                # 첫 번째 객체는 변경되지 않음
Hello, World
>>>

그러나, 이것들을 가변 메모리에 대한 포인터를 예상하는 함수에 전달하지 않도록 주의해야 합니다. 가변 메모리 블록이 필요하다면, ctypes에는 다양한 방법으로 이를 만드는 create_string_buffer() 함수가 있습니다. 현재 메모리 블록 내용은 raw 프로퍼티를 사용하여 액세스(또는 변경)할 수 있습니다; NUL 종료 문자열로 액세스하려면 value 프로퍼티를 사용하십시오:

>>> from ctypes import *
>>> p = create_string_buffer(3)            # NUL 바이트로 초기화된 3바이트 버퍼 생성
>>> print(sizeof(p), repr(p.raw))
3 b'\x00\x00\x00'
>>> p = create_string_buffer(b"Hello")     # NUL 종단 문자열을 포함하는 버퍼 생성
>>> print(sizeof(p), repr(p.raw))
6 b'Hello\x00'
>>> print(repr(p.value))
b'Hello'
>>> p = create_string_buffer(b"Hello", 10) # 10바이트 버퍼 생성
>>> print(sizeof(p), repr(p.raw))
10 b'Hello\x00\x00\x00\x00\x00'
>>> p.value = b"Hi"
>>> print(sizeof(p), repr(p.raw))
10 b'Hi\x00lo\x00\x00\x00\x00\x00'

The create_string_buffer() function replaces the old c_buffer() function (which is still available as an alias). To create a mutable memory block containing unicode characters of the C type wchar_t, use the create_unicode_buffer() function.

함수 호출하기, 계속

printf는 sys.stdout아니라 실제 표준 출력으로 인쇄하므로, 이 예제는 콘솔 프롬프트에서만 작동하고 IDLE 이나 PythonWin에서는 작동하지 않음에 유의하십시오:

>>> printf = libc.printf
>>> printf(b"Hello, %s\n", b"World!")
Hello, World!
14
>>> printf(b"Hello, %S\n", "World!")
Hello, World!
14
>>> printf(b"%d bottles of beer\n", 42)
42 bottles of beer
19
>>> printf(b"%f bottles of beer\n", 42.5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 2: TypeError: Don't know how to convert parameter 2
>>>

이전에 언급했듯이, 정수, 문자열 및 바이트 객체를 제외한 모든 파이썬 형은 필요한 C 데이터형으로 변환될 수 있도록 해당하는 ctypes 형으로 래핑 되어야 합니다:

>>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14))
An int 1234, a double 3.140000
31
>>>

가변 인자 함수 호출하기

대부분의 플랫폼에서 ctypes를 통해 가변 인자 함수를 호출하는 것은 고정된 수의 매개변수를 가진 함수를 호출하는 것과 정확히 동일합니다. 일부 플랫폼, 특히 Apple Platforms용 ARM64에서는 가변 인자 함수의 호출 규칙이 일반 함수와 다릅니다.

이러한 플랫폼에서는 일반적이고 비가변적인 함수 인자에 대해 argtypes 속성을 지정해야 합니다:

libc.printf.argtypes = [ctypes.c_char_p]

속성을 지정하는 것이 이식성을 저해하지 않으므로, 모든 가변 인자 함수에 대해 항상 :attr:`~_CFuncPtr.argtypes`를 지정하는 것이 권장됩니다.

사용자 정의 데이터형을 사용하여 함수 호출하기

ctypes`의 인자 변환을 사용자 정의 클래스의 인스턴스를 함수 인자로 사용할 있도록 사용자 정의할 수도 있습니다. :mod:!ctypes`는 _as_parameter_ 속성을 찾아서 이를 함수 인자로 사용합니다. 이 속성은 정수, 문자열, 바이트, ctypes 인스턴스 또는 _as_parameter_ 속성이 있는 객체여야 합니다:

>>> class Bottles:
...     def __init__(self, number):
...         self._as_parameter_ = number
...
>>> bottles = Bottles(42)
>>> printf(b"%d bottles of beer\n", bottles)
42 bottles of beer
19
>>>

인스턴스의 데이터를 _as_parameter_ 인스턴스 변수에 저장하고 싶지 않다면, 요청 시 속성을 사용할 수 있게 하는 :deco:`property`를 정의할 수도 있습니다.

필수 인자 형 (함수 프로토타입) 지정하기

argtypes 속성을 설정함으로써 DLL에서 내보내는 함수의 필수 인자 유형을 지정하는 것이 가능합니다.

argtypes`는 C 데이터 타입의 시퀀스여야 합니다 ( :func:!printf` 함수는 형식 문자열에 따라 가변적이고 여러 유형의 매개변수를 받기 때문에 좋은 예시는 아닐 수 있지만, 이 기능을 실험하는 데는 매우 유용합니다:

>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
>>> printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2)
String 'Hi', Int 10, Double 2.200000
37
>>>

포맷을 지정하면 호환되지 않는 인자 형으로부터 보호하고(C 함수의 프로토타입처럼), 유효한 형으로 인자를 변환하려고 시도합니다:

>>> printf(b"%d %d %d", 1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 2: TypeError: 'int' object cannot be interpreted as ctypes.c_char_p
>>> printf(b"%s %d %f\n", b"X", 2, 3)
X 2 3.000000
13
>>>

사용자가 함수 호출에 전달하는 자체 클래스를 정의한 경우, 해당 클래스들이 argtypes 시퀀스에서 사용될 수 있도록 from_param() 클래스 메서드를 구현해야 합니다. from_param() 클래스 메서드는 함수 호출에 전달된 파이썬 객체를 받으며, 이 객체가 적절한지 확인하기 위해 타입 검사를 수행하거나 필요한 작업을 수행해야 하며, 그런 다음 해당 객체 자체, 그 _as_parameter_ 속성 또는 이 경우 C 함수 인자로 전달하려는 모든 것을 반환합니다. 다시 한번, 결과는 정수, 문자열, 바이트, ctypes 인스턴스 또는 _as_parameter_ 속성이 있는 객체여야 합니다.

반환형

기본적으로 함수는 C int 유형을 반환하는 것으로 간주됩니다. 다른 반환 유형은 함수 객체의 restype 속성을 설정하여 지정할 수 있습니다.

The C prototype of time() is time_t time(time_t *). Because time_t might be of a different type than the default return type int, you should specify the restype attribute:

>>> libc.time.restype = c_time_t

인자 타입은 argtypes:: 를 사용하여 지정할 수 있습니다:

>>> libc.time.argtypes = (POINTER(c_time_t),)

첫 번째 인자로 NULL 포인터를 사용하여 함수를 호출하려면, None 을 사용하십시오:

>>> print(libc.time(None))
1150640792

여기는 융통성 있는 예제이며, 문자열 포인터와 문자를 예상하고 문자열에 대한 포인터를 반환하는 strchr() 함수를 사용합니다:

>>> strchr = libc.strchr
>>> strchr(b"abcdef", ord("d"))
8059983
>>> strchr.restype = c_char_p    # c_char_p is a pointer to a string
>>> strchr(b"abcdef", ord("d"))
b'def'
>>> print(strchr(b"abcdef", ord("x")))
None
>>>

위의 ord("x") 호출을 피하고 싶다면, argtypes 속성을 설정할 수 있으며, 두 번째 인자는 단일 문자 파이썬 bytes 객체에서 C char로 변환됩니다:

>>> strchr.restype = c_char_p
>>> strchr.argtypes = [c_char_p, c_char]
>>> strchr(b"abcdef", b"d")
b'def'
>>> strchr(b"abcdef", b"def")
Traceback (most recent call last):
ctypes.ArgumentError: argument 2: TypeError: one character bytes, bytearray or integer expected
>>> print(strchr(b"abcdef", b"x"))
None
>>> strchr(b"abcdef", b"d")
b'def'
>>>

만약 외부 함수가 정수를 반환하는 경우, 호출 가능한 파이썬 객체(예: 함수 또는 클래스)를 restype 속성으로 사용할 수도 있습니다. 이 콜러블은 C 함수가 반환한 정수 로 호출되며, 이 호출의 결과는 함수 호출의 결과로 사용됩니다. 이는 오류 반환 값을 확인하고 자동으로 예외를 발생시키는 데 유용합니다:

>>> GetModuleHandle = windll.kernel32.GetModuleHandleA
>>> def ValidHandle(value):
...     if value == 0:
...         raise WinError()
...     return value
...
>>>
>>> GetModuleHandle.restype = ValidHandle
>>> GetModuleHandle(None)
486539264
>>> GetModuleHandle("something silly")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in ValidHandle
OSError: [Errno 126] The specified module could not be found.
>>>

WinError는 윈도우 FormatMessage() api를 호출하여 에러 코드의 문자열 표현을 가져오고, 예외를 반환하는 함수입니다. WinError는 선택적 에러 코드 매개 변수를 취합니다, 제공하지 않으면 GetLastError()를 호출하여 에러 코드를 가져옵니다.

errcheck 속성을 통해 훨씬 강력한 오류 검사 메커니즘을 사용할 수 있다는 점에 유의하십시오. 자세한 내용은 참조 매뉴얼을 참조하십시오:

포인터 전달하기 (또는: 참조로 매개 변수 전달하기)

때때로 C api 함수는 매개 변수로 데이터형을 가리키는 포인터를 기대합니다, 아마도 해당 위치에 쓰기 위해서, 또는 데이터가 너무 커서 값으로 전달할 수 없어서. 이것은 참조로 매개 변수 전달하기로 알려져 있기도 합니다.

ctypes`는 :func:`byref 함수를 내보내며, 이는 매개 변수를 참조로 전달하는 데 사용됩니다. 동일한 효과는 pointer() 함수로도 얻을 수 있습니다. 하지만 :func:`pointer`는 실제 포인터 객체를 생성하기 때문에 더 많은 작업을 수행하므로, 파이썬 자체에서 포인터 객체가 필요하지 않으면 :func:`byref`를 사용하는 것이 더 빠릅니다:

>>> i = c_int()
>>> f = c_float()
>>> s = create_string_buffer(b'\000' * 32)
>>> print(i.value, f.value, repr(s.value))
0 0.0 b''
>>> libc.sscanf(b"1 3.14 Hello", b"%d %f %s",
...             byref(i), byref(f), s)
3
>>> print(i.value, f.value, repr(s.value))
1 3.1400001049 b'Hello'
>>>

구조체와 공용체

구조체와 공용체는 ctypes 모듈에 정의된 StructureUnion 기본 클래스를 상속해야 합니다. 각 서브클래스는 _fields_ 속성을 정의해야 합니다. _fields_필드 이름필드 타입 을 포함하는 2-튜플 의 리스트여야 합니다:

필드는 c_int`와 같은 :mod:!ctypes` 타입이거나 다른 파생된 ctypes 타입이어야 합니다: 구조체, 공용체, 배열, 포인터:

다음은 xy라는 두 개의 정수가 포함된 POINT 구조체의 간단한 예제이며, 생성자에서 구조체를 초기화하는 방법도 보여줍니다:

>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = [("x", c_int),
...                 ("y", c_int)]
...
>>> point = POINT(10, 20)
>>> print(point.x, point.y)
10 20
>>> point = POINT(y=5)
>>> print(point.x, point.y)
0 5
>>> POINT(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: too many initializers
>>>

그러나, 훨씬 복잡한 구조를 만들 수 있습니다. 구조체는 필드형으로 구조체를 사용하여 다른 구조체를 포함할 수 있습니다.

다음은 upperleftlowerright라는 두 개의 POINT를 포함하는 RECT 구조체입니다:

>>> class RECT(Structure):
...     _fields_ = [("upperleft", POINT),
...                 ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print(rc.upperleft.x, rc.upperleft.y)
0 5
>>> print(rc.lowerright.x, rc.lowerright.y)
0 0
>>>

중첩된 구조체는 여러 가지 방법으로 생성자에서 초기화할 수 있습니다:

>>> r = RECT(POINT(1, 2), POINT(3, 4))
>>> r = RECT((1, 2), (3, 4))

필드 descriptor s는 클래스 에서 검색할 수 있으며, 유용한 정보를 제공할 수 있어 디버깅에 유용합니다. CField:: 를 참조하십시오:

>>> POINT.x
<ctypes.CField 'x' type=c_int, ofs=0, size=4>
>>> POINT.y
<ctypes.CField 'y' type=c_int, ofs=4, size=4>
>>>

경고

:mod:`!ctypes`는 비트 필드가 있는 공용체나 구조체를 값으로 함수에 전달하는 것을 지원하지 않습니다. 32비트 x86에서는 작동할 수 있지만, 일반적으로 작동은 라이브러리가 보장하지 않습니다. 비트 필드가 있는 공용체와 구조체는 항상 포인터로 함수에 전달되어야 합니다:

구조체/공용체 레이아웃, 정렬 및 바이트 순서

기본적으로 구조체와 공용체의 필드는 C 컴파일러가 하는 방식과 동일하게 배치됩니다. 서브클래스 정의에 _layout_ 클래스 속성을 지정하여 이 동작을 완전히 재정의하는 것이 가능합니다. 자세한 내용은 해당 속성 문서를 참조하십시오:

클래스 속성 _pack_ 및/또는 :attr:`~Structure._align_`를 설정하여 필드 또는 구조체 자체의 최대 정렬을 지정할 수 있습니다. 자세한 내용은 해당 속성 문서를 참조하십시오:

ctypes`는 구조체와 공용체에 기본(native) 바이트 순서를 사용합니다. 기본이 아닌 바이트 순서로 구조체를 만들려면 :class:`BigEndianStructure, LittleEndianStructure, BigEndianUnionLittleEndianUnion 베이스 클래스 중 하나를 사용할 수 있습니다. 이러한 클래스는 포인터 필드를 포함할 수 없습니다:

구조체와 공용체의 비트 필드

비트 필드를 포함하는 구조체와 공용체를 생성하는 것이 가능합니다. 비트 필드는 정수 필드에 대해서만 가능하며, 비트 너비는 _fields_ 튜플의 세 번째 항목으로 지정됩니다:

>>> class Int(Structure):
...     _fields_ = [("first_16", c_int, 16),
...                 ("second_16", c_int, 16)]
...
>>> print(Int.first_16)
<ctypes.CField 'first_16' type=c_int, ofs=0, bit_size=16, bit_offset=0>
>>> print(Int.second_16)
<ctypes.CField 'second_16' type=c_int, ofs=0, bit_size=16, bit_offset=16>

메모해야 할 중요한 점은 비트 필드 할당 및 메모리 레이아웃이 C 표준으로 정의된 것이 아니며, 구현 방식이 컴파일러에 따라 다르다는 것입니다. 기본적으로 Python은 현재 플랫폼의 “네이티브” 컴파일러 동작과 일치시키려고 시도할 것입니다. 기본 동작 및 변경 방법에 대한 자세한 내용은 _layout_ 어트리뷰트를 참조하십시오.

배열

배열은 같은 형의 고정 된 수의 인스턴스를 포함하는 시퀀스입니다.

배열형을 만드는 데 권장되는 방법은 데이터형에 양의 정수를 곱하는 것입니다:

TenPointsArrayType = POINT * 10

다음은 다소 인공적인 데이터형의 예입니다. 다른 항목들과 함께 4개의 POINT를 포함하는 구조체입니다:

>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = ("x", c_int), ("y", c_int)
...
>>> class MyStruct(Structure):
...     _fields_ = [("a", c_int),
...                 ("b", c_float),
...                 ("point_array", POINT * 4)]
>>>
>>> print(len(MyStruct().point_array))
4
>>>

인스턴스는 클래스를 호출하는 일반적인 방법으로 만들어집니다:

arr = TenPointsArrayType()
for pt in arr:
    print(pt.x, pt.y)

위 코드는 배열 내용이 0으로 초기화되기 때문에, 일련의 0 0 줄을 인쇄합니다.

올바른 형의 초기화자를 지정할 수도 있습니다:

>>> from ctypes import *
>>> TenIntegers = c_int * 10
>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>>> print(ii)
<c_long_Array_10 object at 0x...>
>>> for i in ii: print(i, end=" ")
...
1 2 3 4 5 6 7 8 9 10
>>>

포인터

포인터 인스턴스는 ctypes 형에 pointer() 함수를 호출하여 생성합니다:

>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>>

포인터 인스턴스는 포인터가 가리키는 객체(위에서는 i 객체)를 반환하는 contents 어트리뷰트를 가집니다:

>>> pi.contents
c_long(42)
>>>

:mod:`!ctypes`는 OOR(원래 객체 반환)을 가지고 있지 않다는 점에 유의하십시오. 속성을 검색할 때마다 새롭고 동등한 객체를 구성합니다:

>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
>>>

다른 c_int 인스턴스를 포인터의 contents 어트리뷰트에 대입하면 포인터는 이 인스턴스가 저장되어있는 메모리 위치를 가리키게 됩니다:

>>> i = c_int(99)
>>> pi.contents = i
>>> pi.contents
c_long(99)
>>>

포인터 인스턴스는 정수로도 인덱싱할 수 있습니다.:

>>> pi[0]
99
>>>

정수 인덱스에 대입하면 가리키고 있는 값이 바뀝니다:

>>> print(i)
c_long(99)
>>> pi[0] = 22
>>> print(i)
c_long(22)
>>>

0이 아닌 인덱스를 사용할 수도 있지만, C에서와 마찬가지로 자신이 하는 일을 알아야 합니다: 임의의 메모리 위치를 액세스하거나 변경할 수 있습니다. 일반적으로 C 함수에서 포인터를 받고, 포인터가 실제로 단일 항목 대신 배열을 가리키는 것을 때만 이 기능을 사용합니다.

장면 뒤에서, pointer() 함수는 단순히 포인터 인스턴스를 생성하는 것 이상을 수행하며, 먼저 포인터 를 생성해야 합니다. 이것은 임의의 ctypes 형을 받아 새로운 형을 반환하는 POINTER() 함수로 처리됩니다:

>>> PI = POINTER(c_int)
>>> PI
<class 'ctypes.LP_c_long'>
>>> PI(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected c_long instead of int
>>> PI(c_int(42))
<ctypes.LP_c_long object at 0x...>
>>>

인자 없이 포인터형을 호출하면 NULL 포인터가 만들어집니다. NULL 포인터는 False 논릿값을 갖습니다:

>>> null_ptr = POINTER(c_int)()
>>> print(bool(null_ptr))
False
>>>

ctypes 는 포인터를 역참조(dereference)할 때 NULL 인지 확인합니다 (하지만 NULL 이 아닌 잘못된 포인터를 역참조하면 Python이 충돌합니다):

>>> null_ptr[0]
Traceback (most recent call last):
    ....
ValueError: NULL pointer access
>>>

>>> null_ptr[0] = 1234
Traceback (most recent call last):
    ....
ValueError: NULL pointer access
>>>

GIL 없이 스레드 안전성

Python 3.13부터 :term:`free-threaded build`에서 :term:`GIL`을 비활성화할 수 있습니다. ctypes에서는 단일 객체에 대한 동시 읽기 및 쓰기는 안전하지만, 여러 객체에 걸친 것은 그렇지 않습니다:

>>> number = c_int(42)
>>> pointer_a = pointer(number)
>>> pointer_b = pointer(number)

위의 경우, GIL이 비활성화된 상태에서 주소에 대해 한 객체가 동시에 읽고 쓸 때만 안전합니다. 따라서 pointer_a 는 여러 스레드 전반에 걸쳐 공유되고 쓰여질 수 있지만, pointer_b 도 같은 작업을 시도하지 않을 경우에 한해서입니다. 이것이 문제라면 메모리 접근을 동기화하기 위해 threading.Lock 사용을 고려해 보십시오:

>>> import threading
>>> lock = threading.Lock()
>>> # 스레드 1
>>> with lock:
...    pointer_a.contents = 24
>>> # 스레드 2
>>> with lock:
...    pointer_b.contents = 42

형 변환

일반적으로 ctypes는 엄격한 타입 검사를 수행합니다. 이것은 함수에 있는 argtypes 목록이나 구조체 정의의 멤버 필드 타입으로 POINTER(c_int) 가 포함된 경우, 정확히 동일한 타입의 인스턴스만 허용된다는 의미입니다. 이 규칙에는 다른 객체를 허용하는 몇 가지 예외가 있습니다. 예를 들어, 포인터 타입 대신 호환 가능한 배열 인스턴스를 전달할 수 있습니다. 따라서 POINTER(c_int) 의 경우, ctypes는 c_int 배열을 허용합니다:

>>> class Bar(Structure):
...     _fields_ = [("count", c_int), ("values", POINTER(c_int))]
...
>>> bar = Bar()
>>> bar.values = (c_int * 3)(1, 2, 3)
>>> bar.count = 3
>>> for i in range(bar.count):
...     print(bar.values[i])
...
1
2
3
>>>

게다가, 함수 인수가 argtypes`에서 포인터 타입(예: ``POINTER(c_int)`)으로 명시적으로 선언된 경우, 포인트된 타입(이 경우 c_int)의 객체를 해당 함수에 전달할 수 있습니다. 이 경우 ctypes가 필요한 byref() 변환을 자동으로 적용합니다.

POINTER 형 필드를 NULL로 설정하려면, None을 대입할 수 있습니다:

>>> bar.values = None
>>>

때로는 비호환적인 타입의 인스턴스를 가질 수도 있습니다. C에서는 한 타입을 다른 타입으로 캐스팅할 수 있습니다. ctypes`는 같은 방식으로 사용할 있는 :func:`cast 함수를 제공합니다. 위에 정의된 Bar 구조체는 values 필드에 대해 POINTER(c_int) 포인터 또는 c_int 배열을 허용하지만, 다른 타입의 인스턴스는 허용하지 않습니다:

>>> bar.values = (c_byte * 4)()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
>>>

이럴 때, cast() 함수가 편리합니다.

cast() 함수는 ctypes 인스턴스를 다른 ctypes 데이터형에 대한 포인터로 변환하는 데 사용할 수 있습니다. cast()는 두 개의 매개 변수, 어떤 종류의 포인터로 변환될 수 있는 ctypes 객체와 ctypes 포인터형을 받아들입니다. 첫 번째 인자와 같은 메모리 블록을 참조하는 두 번째 인자의 인스턴스를 반환합니다:

>>> a = (c_byte * 4)()
>>> cast(a, POINTER(c_int))
<ctypes.LP_c_long object at ...>
>>>

따라서, cast()Bar 구조체의 values 필드에 대입하는 데 사용할 수 있습니다:

>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print(bar.values[0])
0
>>>

불완전한 형

불완전한 형은 멤버가 아직 지정되지 않은 구조체, 공용체 또는 배열입니다. C에서, 이것들은 나중에 정의되는 전방 선언(forward declaration)으로 지정됩니다:

struct cell; /* 전방 선언 */

struct cell {
    char *name;
    struct cell *next;
};

ctypes 코드로 그대로 옮기면 이렇게 되지만, 작동하지는 않습니다:

>>> class cell(Structure):
...     _fields_ = [("name", c_char_p),
...                 ("next", POINTER(cell))]
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in cell
NameError: name 'cell' is not defined
>>>

왜냐하면 새로운 class cell``이 클래스 구문 자체에 존재하지 않기 때문입니다. :mod:`!ctypes`에서, 우리는 ``cell 클래스를 정의하고 클래스 구문 이후에 _fields_ 어트리뷰트를 설정할 수 있습니다:

>>> from ctypes import *
>>> class cell(Structure):
...     pass
...
>>> cell._fields_ = [("name", c_char_p),
...                  ("next", POINTER(cell))]
>>>

해 봅시다. 우리는 두 개의 cell 인스턴스를 만들고, 서로를 가리키도록 한 다음, 마지막으로 포인터 체인을 몇 번 따라갑니다:

>>> c1 = cell()
>>> c1.name = b"foo"
>>> c2 = cell()
>>> c2.name = b"bar"
>>> c1.next = pointer(c2)
>>> c2.next = pointer(c1)
>>> p = c1
>>> for i in range(8):
...     print(p.name, end=" ")
...     p = p.next[0]
...
foo bar foo bar foo bar foo bar
>>>

콜백 함수

ctypes 는 Python 콜러블로부터 C에서 호출 가능한 함수 포인터를 생성할 수 있게 합니다. 이들은 때로 콜백 함수(callback functions) 라고 불리기도 합니다.

먼저, 콜백 함수를 위한 클래스를 만들어야 합니다. 클래스는 호출 규칙, 반환형 및 이 함수가 받는 인자의 수와 형을 알고 있습니다.

CFUNCTYPE() 팩토리 함수는 cdecl 호출 규칙을 사용하여 콜백 함수의 형을 만듭니다. 윈도우에서, WINFUNCTYPE() 팩토리 함수는 stdcall 호출 규칙을 사용하여 콜백 함수 형을 만듭니다.

이러한 팩토리 함수는 모두 첫 번째 인자로 결과 형을, 나머지 인자로 콜백 함수가 기대하는 인자 형들로 호출됩니다.

여기에서는 콜백 함수의 도움을 받아 항목을 정렬하는 데 사용되는 표준 C 라이브러리의 qsort() 함수를 사용하는 예를 제시하겠습니다. :c:func:`!qsort`는 정수 배열을 정렬하는 데 사용될 것입니다:

>>> IntArray5 = c_int * 5
>>> ia = IntArray5(5, 1, 7, 33, 99)
>>> qsort = libc.qsort
>>> qsort.restype = None
>>>

:func:`!qsort`와는 데이터가 저장된 곳에 대한 포인터, 데이터 배열의 항목 개수, 항목 하나의 크기, 그리고 비교 함수(콜백)에 대한 포인터를 함께 호출해야 합니다. 콜백은 그러면 두 개의 아이템 포인터와 함께 호출되며, 첫 번째 항목이 두 번째 항목보다 작으면 음수 정수를, 같으면 0을, 그렇지 않으면 양수 정수를 반환해야 합니다.

따라서 콜백 함수는 정수에 대한 포인터들을 받고 정수를 반환해야 합니다. 먼저 콜백 함수를 위한 을 만듭니다:

>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
>>>

시작하기 위해, 전달된 값을 보여주는 간단한 콜백이 있습니다:

>>> def py_cmp_func(a, b):
...     print("py_cmp_func", a[0], b[0])
...     return 0
...
>>> cmp_func = CMPFUNC(py_cmp_func)
>>>

결과:

>>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 5 7
py_cmp_func 1 7
>>>

이제 실제로 두 항목을 비교하여 유용한 결과를 반환할 수 있습니다:

>>> def py_cmp_func(a, b):
...     print("py_cmp_func", a[0], b[0])
...     return a[0] - b[0]
...
>>>
>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 1 7
py_cmp_func 5 7
>>>

쉽게 확인할 수 있듯이, 배열은 이제 정렬되었습니다:

>>> for i in ia: print(i, end=" ")
...
1 5 7 33 99
>>>

함수 팩토리는 데코레이터 팩토리로 사용할 수 있으므로, 다음과 같이 작성할 수도 있습니다:

>>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
... def py_cmp_func(a, b):
...     print("py_cmp_func", a[0], b[0])
...     return a[0] - b[0]
...
>>> qsort(ia, len(ia), sizeof(c_int), py_cmp_func)
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 1 7
py_cmp_func 5 7
>>>

참고

C 코드에서 사용되는 동안 CFUNCTYPE() 객체에 대한 참조를 유지해야 합니다. :mod:`!ctypes`는 그렇지 않으며, 여러분이 그러지 않으면 가비지 수집되어 콜백이 발생할 때 프로그램이 충돌할 수도 있습니다.:

또한, 콜백 함수가 파이썬 제어 바깥에서 만들어진 스레드(예를 들어, 콜백을 호출하는 외부 코드)에서 호출되면, ctypes는 모든 호출에 대해 새로운 더미 파이썬 스레드를 만듭니다. 이 동작은 대부분 적합하지만, threading.local에 저장된 값은, 같은 C 스레드에서 호출되는 여러 콜백에서 살아남을 수 없음을 뜻합니다.

dll에서 내 보낸 값을 액세스하기

일부 공유 라이브러리는 함수만 내보내는 것이 아니라 변수도 내보냅니다. Python 라이브러리 자체의 예로는 :c:data:`Py_Version`이 있으며, 이는 단일 상수 정수로 인코딩된 Python 런타임 버전 번호입니다.:

ctypes 는 해당 타입의 in_dll() 클래스 메서드를 사용해 다음과 같은 값에 액세스할 수 있습니다. pythonapi 는 Python C api에 접근하는 사전 정의된 심볼입니다:

>>> version = ctypes.c_int.in_dll(ctypes.pythonapi, "Py_Version")
>>> print(hex(version.value))
0x30c00a0

포인터의 사용법도 보여주는 확장 예제는 파이썬이 내 보낸 PyImport_FrozenModules 포인터에 액세스합니다.

해당 값에 대한 문서를 인용하면:

이 포인터는 모든 멤버가 NULL 또는 0인 하나를 포함하여, _frozen 레코드 배열을 가리키도록 초기화됩니다. 프리즈된 모듈이 임포트되면 이 테이블에서 검색됩니다. 타사 코드는 이 기능을 속임수 삼아 동적으로 생성된 프리즈드 모듈 컬렉션을 제공할 수도 있습니다.:

따라서, 이 포인터를 조작하는 것이 유용하게 입증될 수도 있습니다. 예제 크기를 제한하기 위해, :mod:`!ctypes`로 이 테이블을 읽는 방법만 보여줍니다:

>>> from ctypes import *
>>>
>>> class struct_frozen(Structure):
...     _fields_ = [("name", c_char_p),
...                 ("code", POINTER(c_ubyte)),
...                 ("size", c_int),
...                 ("get_code", POINTER(c_ubyte)),  # 함수 포인터
...                ]
...
>>>

:c:struct:`_frozen`의 데이터 타입을 정의했기 때문에, 테이블에 대한 포인터를 얻을 수 있습니다:

>>> FrozenTable = POINTER(struct_frozen)
>>> table = FrozenTable.in_dll(pythonapi, "_PyImport_FrozenBootstrap")
>>>

tablestruct_frozen 레코드의 배열에 대한 포인터이므로, 이터레이션할 수 있습니다. 하지만 포인터는 크기가 없으므로 루프를 종료하는 방법이 필요합니다. 조만간 액세스 위반 등으로 인해 충돌이 발생할 수 있으므로, NULL 엔트리가 발견되자마자 루프에서 벗어나는 것이 좋습니다:

>>> for item in table:
...     if item.name is None:
...         break
...     print(item.name.decode("ascii"), item.size)
...
_frozen_importlib 31764
_frozen_importlib_external 41499
zipimport 12345
>>>

표준 파이썬이 프로즌 모듈과 프로즌 패키지(음수 size 멤버로 표시됨)를 가지고 있다는 사실은 잘 알려지지 않았으며, 테스트용으로만 사용됩니다. 예를 들어 import __hello__를 시도해보십시오.

의외의 것들

:mod:`!ctypes`에는 여러분이 기대하는 것과 실제로 발생하는 것이 다른 가장자리 부분이 일부 존재합니다.:

다음 예제를 고려해보십시오:

>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = ("x", c_int), ("y", c_int)
...
>>> class RECT(Structure):
...     _fields_ = ("a", POINT), ("b", POINT)
...
>>> p1 = POINT(1, 2)
>>> p2 = POINT(3, 4)
>>> rc = RECT(p1, p2)
>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)
1 2 3 4
>>> # 두 포인트의 위치를 바꿉니다
>>> rc.a, rc.b = rc.b, rc.a
>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)
3 4 3 4

흠. 아마도 마지막 문장이 3 4 1 2를 인쇄할 것으로 기대했을 겁니다. 어떻게 된 걸까요? 위의 rc.a, rc.b = rc.b, rc.a 줄의 단계는 다음과 같습니다:

>>> temp0, temp1 = rc.b, rc.a
>>> rc.a = temp0
>>> rc.b = temp1
>>>

temp0temp1은 여전히 위의 rc 객체의 내부 버퍼를 사용하는 객체입니다. 따라서 rc.a = temp0를 실행하면 temp0의 버퍼 내용이 rc의 버퍼로 복사됩니다. 이것은, 결과적으로 temp1의 내용을 변경합니다. 따라서 마지막 대입인 rc.b = temp1은 기대하는 효과를 주지 못합니다.

Structure, Union 및 Array에서 서브 객체를 가져오는 것은 서브 객체를 복사하지 않고, 대신 루트 객체의 하부 버퍼에 액세스하는 래퍼 객체를 가져온다는 점에 유의하십시오.

예상과 다른 행동을 하는 또 다른 예는 다음과 같습니다:

>>> s = c_char_p()
>>> s.value = b"abc def ghi"
>>> s.value
b'abc def ghi'
>>> s.value is s.value
False
>>>

참고

c_char_p로 인스턴스를 만든 객체는 바이트열이나 정수로 설정된 value만 가질 수 있습니다.

False를 인쇄하는 이유는 무엇일까요? ctypes 인스턴스는 메모리 블록과 메모리 내용에 액세스하는 어떤 디스크립터를 포함하는 객체입니다. 메모리 블록에 파이썬 객체를 저장하면 객체 자체를 저장하지 않고, 대신 객체의 내용을 저장합니다. 내용에 다시 액세스하면 매번 새로운 파이썬 객체가 생성됩니다!

가변 크기 데이터형

:mod:`!ctypes`는 가변 크기 배열 및 구조체에 대한 일부 지원을 제공합니다.:

resize() 함수는 기존 ctypes 객체의 메모리 버퍼 크기를 바꾸는 데 사용할 수 있습니다. 이 함수는 객체를 첫 번째 인자로 가져오고, 바이트 단위의 요청 된 크기를 두 번째 인자로 가져옵니다. 메모리 블록을 객체 형이 지정하는 원래 메모리 블록보다 작게 만들 수 없습니다. 시도하면 ValueError가 발생합니다:

>>> short_array = (c_short * 4)()
>>> print(sizeof(short_array))
8
>>> resize(short_array, 4)
Traceback (most recent call last):
    ...
ValueError: minimum size is 8
>>> resize(short_array, 32)
>>> sizeof(short_array)
32
>>> sizeof(type(short_array))
8
>>>

훌륭합니다, 하지만 이 배열에 포함된 추가 요소에 어떻게 액세스할 수 있습니까? 형은 여전히 4개의 요소만 알고 있으므로, 다른 요소에 액세스하면 에러가 발생합니다:

>>> short_array[:]
[0, 0, 0, 0]
>>> short_array[7]
Traceback (most recent call last):
    ...
IndexError: invalid index
>>>

:mod:`!ctypes`에서 가변 크기 데이터 타입을 사용하는 또 다른 방법은, 파이썬의 동적 특성을 이용하여 필요한 크기가 이미 알려진 후에 개별적으로 데이터 타입을 (재)정의하는 것입니다.:

ctypes 레퍼런스

공유 라이브러리 로드하기

파이썬 프로세스에 공유 라이브러리를 로드하는 방법에는 여러 가지가 있습니다. 한 가지 방법은 CDLL 또는 그 하위 클래스를 인스턴스화하는 것입니다:

class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

로드된 공유 라이브러리를 나타냅니다.:

이 라이브러리의 함수들은 표준 C 호출 규칙을 사용하며, int 를 반환하는 것으로 가정합니다. Python의 전역 인터프리터 록 \은 이 라이브러리에서 내보낸 모든 함수를 호출하기 전에 해제되고 나중에 다시 획득됩니다. 다른 기능 동작을 위해서는 하위 클래스를 사용하세요: OleDLL, WinDLL, 또는 PyDLL:

이미 로드된 공유 라이브러리에 대한 기존의 handle 가 있다면, 이 값을 handle 인수로 전달하여 열린 라이브러리를 새로운 CDLL 객체로 래핑할 수 있습니다. 이 경우, name 은 오직 _name 속성을 설정하는 데 사용될 뿐이며, 조정 및/또는 검증될 수 있습니다.:

만약 handleNone 이면, 기본 플랫폼의 dlopen(3) 또는 LoadLibraryExW \ 함수가 라이브러리를 프로세스에 로드하고 핸들을 얻는 데 사용됩니다.:

name 은 열고자 하는 공유 라이브러리의 경로 이름입니다. name 에 경로 구분자가 포함되어 있지 않다면, 라이브러리는 플랫폼별 방식으로 찾아집니다.:

Windows에서는 .DLL 접미사가 누락될 수 있습니다. (자세한 내용은 LoadLibraryExW \ 문서 참조.) 다른 플랫폼별 접두사 및 접미사(예:, lib, .so, .dylib 또는 버전 번호)는 name 에 반드시 포함되어야 하며, 자동으로 추가되지 않습니다. 더 자세한 내용은 공유 라이브러리 찾기 를 참조하십시오.:

비-Windows 시스템에서는 nameNone 일 수 있습니다. 이 경우, dlopen()NULL 과 함께 호출되어 메인 프로그램을 “라이브러리”로 엽니다. (일부 시스템은 name 이 비어 있을 때 동일하게 처리합니다. None/NULL 이 더 이식성이 높습니다.):

CPython 구현 상세

CPython이 libc 에 연결되어 있기 때문에, C 표준 라이브러리에 액세스하려면 종종 None name 을 사용합니다:

>>> printf = ctypes.CDLL(None).printf
>>> printf.argtypes = [ctypes.c_char_p]
>>> printf(b"hello\n")
hello
6

Python C API에 액세스하려면 플랫폼 전반에서 작동하는 :py:data:`ctypes.pythonapi`를 사용하는 것이 좋습니다.

mode 매개 변수는 라이브러리가 로드되는 방법을 지정하는 데 사용될 수 있습니다. 자세한 내용은, dlopen(3) 매뉴얼 페이지를 참조하십시오. 윈도우에서는, mode가 무시됩니다. posix 시스템에서는 RTLD_NOW가 항상 추가되며 구성할 수 없습니다.

use_errno 매개 변수를 true로 설정하면, 시스템 errno 에러 번호에 안전하게 액세스할 수 있도록 하는 ctypes 메커니즘이 활성화됩니다. ctypes 는 시스템의 errno 변수의 스레드 로컬 복사본을 유지합니다. use_errno=True 를 사용하여 생성된 외부 함수를 호출하면, 함수 호출 전의 errno 값이 ctypes 내부 복사본으로 교체되고, 이는 함수 호출 직후에도 동일하게 발생합니다.

ctypes.get_errno() 함수는 ctypes 내부 사본의 값을 반환하고, ctypes.set_errno() 함수는 ctypes 내부 사본을 새 값으로 변경하고 이전 값을 반환합니다.

use_last_error 매개 변수를 true로 설정하면, GetLastError()SetLastError() 윈도우 API 함수에 의해 관리되는 윈도우 에러 코드에 대해 동일한 메커니즘이 활성화됩니다. :func:`ctypes.get_last_error`와 :func:`ctypes.set_last_error`는 윈도우 에러 코드의 ctypes 내부 복사본을 요청하고 변경하는 데 사용됩니다.

winmode 매개 변수는 Windows에서 라이브러리가 어떻게 로드될지 지정하는 데 사용됩니다 ( mode 는 무시됩니다). 이 매개 변수는 Win32 API LoadLibraryExW 플래그 매개 변수에 유효한 모든 값을 받을 수 있습니다. 생략하면, DLL 하이재킹와 같은 문제를 피하는 가장 안전한 DLL 로드를 반환하는 기본 플래그가 사용됩니다. DLL의 전체 경로를 전달하는 것이 올바른 라이브러리와 종속성이 로드되도록 보장하는 가장 안전한 방법입니다.

윈도우에서는 DLL 이름이 존재하더라도 CDLL 인스턴스 생성이 실패할 수 있습니다. 로드된 DLL의 종속 DLL을 찾을 수 없을 때, “[WinError 126] The specified module could not be found” 메시지로 OSError 에러가 발생합니다. 윈도우 API가 정보를 반환하지 않아서 이 에러 메시지에는 누락된 DLL의 이름이 포함되어 있지 않고, 이 에러를 진단하기 어렵게 만듭니다. 이 에러를 해결하고 찾을 수 없는 DLL을 확인하려면, 윈도우 디버깅과 추적 도구를 사용하여 종속 DLL 목록을 찾고 찾을 수 없는 DLL을 확인해야 합니다.

더 보기

Microsoft DUMPBIN tool – DLL 종속 항목을 찾는 도구입니다.

버전 3.8에서 변경: winmode 매개 변수가 추가되었습니다.

버전 3.12에서 변경: name 매개 변수는 이제 :term:`경로류 객체 <path-like object>`가 될 수 있습니다.

이 클래스의 인스턴스는 공개 메서드가 없습니다. 공유 라이브러리에 의해 내보낸 함수는 어트리뷰트 또는 인덱스로 액세스할 수 있습니다. 어트리뷰트를 통해 함수에 액세스하는 것은 결과를 캐싱하므로, 반복적으로 액세스하면 매번 동일한 객체가 반환됨에 유의하십시오. 한편, 인덱스를 통해 액세스하면 매번 새로운 객체가 반환됩니다:

>>> from ctypes import CDLL
>>> libc = CDLL("libc.so.6")  # Linux에서
>>> libc.time == libc.time
True
>>> libc['time'] == libc['time']
False

다음 공개 어트리뷰트를 사용할 수 있습니다. 이름이 밑줄로 시작하는 것은 내보낸 함수 이름과 충돌을 피하기 위해서입니다:

_handle

라이브러리에 액세스하는 데 사용되는 시스템 핸들.

_name

생성자에서 전달된 라이브러리의 이름.

class ctypes.OleDLL

일반적인 정보는 상위 클래스인 :py:class:`~ctypes.CDLL`를 참조하십시오.

이 라이브러리의 함수들은 stdcall 호출 규칙을 사용하며, 윈도우 고유의 HRESULT 코드를 반환하는 것으로 가정합니다. HRESULT 값에는 함수 호출이 실패했는지 또는 성공했는지를 지정하는 정보와 추가 에러 코드가 포함됩니다. 반환 값이 실패를 알리면, :class:`OSError`가 자동으로 발생합니다.

가용성: Windows

버전 3.3에서 변경: :exc:`WindowsError`를 사용하면 이전에 예외가 발생했었으며, 현재는 :exc:`OSError`의 별칭입니다.

class ctypes.WinDLL

일반적인 정보는 상위 클래스인 :py:class:`~ctypes.CDLL`를 참조하십시오.

이 라이브러리의 함수들은 stdcall 호출 규칙을 사용하며, 기본적으로 :c:expr:`int`를 반환하는 것으로 가정됩니다.

가용성: Windows

class ctypes.PyDLL

일반적인 정보는 상위 클래스인 :py:class:`~ctypes.CDLL`를 참조하십시오.

이 라이브러리에 있는 함수들이 호출될 때, Python GIL은 함수 호출 중에 해제되지 않으며, 함수 실행 후에는 Python 에러 플래그가 확인됩니다. 에러 플래그가 설정된 경우, Python 예외가 발생합니다.

따라서, 이것은 Python C API 함수를 직접 호출할 때만 유용합니다.

ctypes.RTLD_GLOBAL

mode 매개 변수에 사용하는 플래그. 이 플래그를 사용할 수 없는 플랫폼에서는, 정수 0으로 정의됩니다.

ctypes.RTLD_LOCAL

mode 매개 변수에 사용하는 플래그. 이 플래그를 사용할 수 없는 플랫폼에서는, RTLD_GLOBAL과 같습니다.

ctypes.DEFAULT_MODE

공유 라이브러리를 로드하는 데 사용되는 기본 모드. OSX 10.3에서는 RTLD_GLOBAL이고, 그렇지 않으면 RTLD_LOCAL과 같습니다.

공유 라이브러리는 또한 LibraryLoader 클래스의 인스턴스인 미리 제작된 객체 중 하나를 사용하여 로드될 수 있습니다. 이는 LoadLibrary() 메서드를 호출하거나, 로더 인스턴스의 어트리뷰트로 라이브러리를 검색하는 방식으로 가능합니다.

class ctypes.LibraryLoader(dlltype)

공유 라이브러리를 로드하는 클래스. dlltypeCDLL, PyDLL, WinDLL 또는 OleDLL 형 중 하나여야 합니다.

:meth:`!__getattr__`는 특별한 동작을 합니다: 라이브러리 로더 인스턴스의 어트리뷰트로 접근하여 공유 라이브러리를 로드할 수 있게 합니다. 결과는 캐시되므로, 반복적인 어트리뷰트 접근은 매번 동일한 라이브러리를 반환합니다.

LoadLibrary(name)

공유 라이브러리를 프로세스에 로드하고 반환합니다. 이 메서드는 항상 라이브러리의 새 인스턴스를 반환합니다.

다음과 같은 사전 작성된 로더를 사용할 수 있습니다:

ctypes.cdll

CDLL 인스턴스를 만듭니다.

ctypes.windll

WinDLL 인스턴스를 생성합니다.

가용성: Windows

ctypes.oledll

OleDLL 인스턴스를 생성합니다.

가용성: Windows

ctypes.pydll

PyDLL 인스턴스를 만듭니다.

ctypes.pythonapi

어트리뷰트로 Python C API 함수를 노출하는 PyDLL`의 인스턴스입니다. 모든 함수는 C :c:expr:`int`를 반환하는 것으로 가정되지만, 이는 항상 진실인 것은 아니므로, 함수들을 사용하려면 올바른 :attr:!restype` 어트리뷰트를 할당해야 합니다.

이러한 객체를 통해 라이브러리를 로드하면 라이브러리를 로드하는 데 사용된 이름인 name 문자열 인자로 감사 이벤트(auditing event) ctypes.dlopen을 발생시킵니다.

로드된 라이브러리에서 함수에 액세스하면 인자 library(라이브러리 객체)와 name(문자열이나 정수로 심볼의 이름)으로 감사 이벤트 ctypes.dlsym을 발생시킵니다.

객체 대신 라이브러리 핸들만 사용 가능한 경우, 함수에 액세스하면 인자 handle(원시 라이브러리 핸들)과 name으로 감사 이벤트 ctypes.dlsym/handle을 발생시킵니다.

공유 라이브러리 찾기

컴파일된 언어로 프로그래밍할 때, 공유 라이브러리는 프로그램을 컴파일하거나 링크하는 시점과 프로그램이 실제로 실행될 때 접근됩니다. 프로그래머가 짧은 이름을 지정하면, C 컴파일러, 링커 및 런타임 동적 라이브러리 로더가 시스템별 방식으로 상호 작용하여 로드할 라이브러리의 파일 이름을 찾아냅니다.

플랫폼에 따라 짧은 이름과 파일 이름 간의 매핑이 일관되게 노출되는 것은 아니지만, ctypes.util 모듈은 해당 매칭을 시도하는 find_library() 함수를 제공합니다. 하지만 하위 호환성 문제 때문에 새 플랫폼 및 구성에 맞춰 동작을 조정하기 어려워 이 함수는 soft deprecated 상태입니다.

ctypes`로 공유 라이브러리를 래핑하는 경우, 개발 시점에 공유 라이브러리 이름을 결정하고 이를 래퍼 모듈에 하드 코딩하는 것을 고려해 보세요. 이렇게 하면 런타임에 :func:!find_library`를 사용하여 라이브러리를 찾을 필요가 없습니다. 또한 사용자에게 사용할 라이브러리를 선택할 수 있도록 구성 옵션이나 환경 변수를 추가하거나, 기본 또는 대체재로 :func:`!find_library`를 사용하는 것도 고려할 수 있습니다.

ctypes.util.find_library(name)

라이브러리를 찾아 경로명을 반환합니다.

namelib 와 같은 접두사, .so, .dylib 또는 버전 번호가 없는 “짧은” 라이브러리 이름입니다. (이것은 posix 링커 옵션 -l 에 사용되는 형식입니다.) 그 결과는 CDLL 에 전달하기 적합한 형식으로 되어 있습니다.

라이브러리를 찾을 수 없으면, None 을 반환합니다.

정확한 기능은 시스템에 따라 달라지며, Python에서 사용되는 (또는 Python이 사용하는) 컴파일러, 링커 및 로더의 동작과 일치하는 것이 보장되지 않습니다. 이 함수는 기본값이나 대체재로만 사용하는 것을 권장합니다.

버전 3.15부터 약하게 폐지 <Soft deprecated>: 이 함수는 작동하는 경우에 대비하여 유지되지만, 추가적인 플랫폼 및 구성에 대해서 업데이트될 것으로 기대되지는 않습니다.

리눅스에서 find_library`는 라이브러리 파일을 찾기 위해 외부 프로그램(`()/sbin/ldconfig``, gcc, objdumpld)을 실행하려고 시도합니다. 이 프로그램들의 출력이 Python이 사용하는 동적 링커와 일치하지 않는 경우, 이 함수의 결과가 오해의 소지가 있을 수 있습니다.

버전 3.6에서 변경: 리눅스에서, 다른 수단으로 라이브러리를 찾을 수 없으면, 라이브러리 검색 시 환경 변수 LD_LIBRARY_PATH의 값이 사용됩니다.

여기 예제가 있습니다:

>>> from ctypes.util import find_library
>>> find_library("m")
'libm.so.6'
>>> find_library("c")
'libc.so.6'
>>> find_library("bz2")
'libbz2.so.1.0'
>>>

macOS 및 Android에서 :func:`!find_library`는 시스템의 표준 명명 규칙과 경로를 사용하여 라이브러리를 찾고, 성공할 경우 전체 파일 경로를 반환합니다:

>>> from ctypes.util import find_library
>>> find_library("c")
'/usr/lib/libc.dylib'
>>> find_library("m")
'/usr/lib/libm.dylib'
>>> find_library("bz2")
'/usr/lib/libbz2.dylib'
>>> find_library("AGL")
'/System/Library/Frameworks/AGL.framework/AGL'
>>>

Windows에서는 find_library() 가 시스템 검색 경로를 따라 검색하여 전체 파일 경로를 반환하지만, 미리 정의된 명명 규칙이 없기 때문에 find_library("c") 과 같은 호출은 실패하고 None 을 반환합니다.

ctypes.util.find_msvcrt()

Python 및 확장 모듈에서 사용되는 VC 런타임 라이브러리의 파일 이름을 반환합니다.

라이브러리 이름이 결정될 수 없는 경우, None 이 반환됩니다. 특히 최근 버전의 VC 런타임 라이브러리는 직접 로드할 수 없기 때문에 이럴 수 있습니다.

예를 들어, free(void *)에 대한 호출로 확장 모듈에 의해 할당된 메모리를 해제해야 하면, 메모리를 할당한 것과 같은 라이브러리에 있는 함수를 사용하는 것이 중요합니다.

가용성: Windows

로드된 공유 라이브러리 나열하기

공유 라이브러리에서 로드된 코드를 사용하는 코드를 작성할 때, 현재 프로세스에 이미 어떤 공유 라이브러리가 로드되어 있는지 아는 것이 유용할 수 있습니다.

ctypes.util 모듈은 dllist() 함수를 제공하여, 현재 프로세스에 이미 로드된 공유 라이브러리를 결정하는 데 도움을 주기 위해 다양한 플랫폼에서 제공되는 여러 API를 호출합니다.

이 함수의 정확한 출력은 시스템에 따라 다릅니다. 대부분의 플랫폼에서 이 목록의 첫 번째 항목은 현재 프로세스 자체를 나타내며, 비어 있는 문자열일 수 있습니다. 예를 들어, glibc 기반 리눅스의 경우 반환되는 결과는 다음과 비슷할 수 있습니다:

>>> from ctypes.util import dllist
>>> dllist()
['', 'linux-vdso.so.1', '/lib/x86_64-linux-gnu/libm.so.6', '/lib/x86_64-linux-gnu/libc.so.6', ... ]

외부 함수

이전 섹션에서 설명했듯이, 외부 함수는 로드된 공유 라이브러리의 속성으로 접근할 수 있습니다. 이렇게 생성된 함수 객체들은 기본적으로 어떤 수의 인자든 받으며, 모든 ctypes 데이터 인스턴스를 인자로 받고, 라이브러리 로더가 지정한 기본 결과 유형을 반환합니다.

이들은 사적인 로컬 클래스 _FuncPtr ( ctypes`에서는 노출되지 않음)의 인스턴스이며, 클래스는 사적인 :class:`_CFuncPtr 클래스를 상속받습니다:

>>> import ctypes
>>> lib = ctypes.CDLL(None)
>>> issubclass(lib._FuncPtr, ctypes._CFuncPtr)
True
>>> lib._FuncPtr is ctypes._CFuncPtr
False
class ctypes._CFuncPtr

C 호출 가능한 외부 함수의 베이스 클래스.

외부 함수의 인스턴스는 C 호환 데이터형이기도 합니다; C 함수 포인터를 나타냅니다.

이 동작은 외부 함수 객체의 특수 어트리뷰트에 대입하여 사용자 정의할 수 있습니다.

restype

외부 함수의 결과 유형을 지정하기 위해 ctypes 타입을 지정합니다. 아무것도 반환하지 않는 함수인 경우 void 에 대해서는 None 을 사용하십시오.

ctypes 형이 아닌 호출 가능한 Python 객체를 할당할 수 있습니다. 이 경우 함수는 C int 를 반환하는 것으로 가정되며, 해당 호출 가능 객체에 이 정수가 전달되어 추가적인 처리나 오류 확인을 수행할 수 있게 합니다. 이는 사용이 더 이상 권장되지 않습니다. 보다 유연한 사후 처리 또는 오류 확인을 위해서는 ctypes 데이터 타입을 restype 로 지정하고 콜러블을 errcheck 속성에 할당하십시오.

argtypes

ctypes 형의 튜플을 대입하여 함수가 받아들이는 인자 형을 지정합니다. stdcall 호출 규칙을 사용하는 함수는 이 튜플의 길이와 같은 수의 인자로만 호출할 수 있습니다; C 호출 규칙을 사용하는 함수는 추가적인 지정되지 않은 인자도 허용합니다.

외부 함수를 호출할 때, 실제 인자 각각은 argtypes 튜플 내의 항목들에 대해 from_param() 클래스 메서드로 전달됩니다. 이 메서드는 실제 인자를 외부 함수가 수용하는 객체 형식으로 조정할 수 있게 합니다. 예를 들어, argtypes 튜플 내의 c_char_p 항목은 전달된 문자열을 ctypes 변환 규칙을 사용하여 바이트 객체로 변환합니다.

새 기능: 이제 argtypes에 ctypes 형이 아닌 항목들을 넣을 수 있게 되었습니다. 다만, 각 항목은 인자로 사용 가능 값(정수, 문자열, ctypes 인스턴스)을 반환하는 from_param() 메서드를 가지고 있어야 합니다. 이를 통해 사용자 정의 객체를 함수 매개변수로 사용할 수 있는 어댑터를 정의할 수 있습니다.

errcheck

이 어트리뷰트에 파이썬 함수나 다른 콜러블을 대입합니다. 콜러블은 3개 이상의 인자로 호출됩니다:

callable(result, func, arguments)

resultrestype 속성에 지정된 대로 외부 함수가 반환하는 값입니다.

func는 외부 함수 객체 자체이며, 같은 콜러블 객체를 재사용하여 여러 함수의 결과를 확인하거나 사후 처리할 수 있도록 합니다.

arguments는 원래 함수 호출에 전달된 매개 변수를 포함하는 튜플입니다. 사용된 인자에 따라 동작을 특수화할 수 있도록 합니다.

이 함수가 반환하는 객체는 외부 함수 호출에서 반환되지만, 결괏값을 확인하고 외부 함수 호출이 실패하면 예외를 발생시킬 수도 있습니다.

Windows에서 외부 함수 호출이 시스템 예외를 발생시키는 경우 (예: 액세스 위반으로 인해), 이는 포착되어 적절한 Python 예외로 대체됩니다. 또한, 인자 code 를 가진 감사 이벤트 ctypes.set_exception 이 발생하여, 감사 훅이 이 예외를 자신만의 것으로 대체할 수 있게 합니다.

외부 함수 호출을 수행하는 몇 가지 방법과 이 모듈의 일부 함수들은 function pointerarguments 인자를 가진 감사 이벤트 `ctypes.call_function`을 발생시킬 수 있습니다.

함수 프로토타입

함수 프로토타입의 인스턴스를 만들어서 외부 함수를 만들 수도 있습니다. 함수 프로토타입은 C의 함수 프로토타입과 비슷합니다; 구현을 정의하지 않고 함수(반환형, 인자형, 호출 규칙)를 설명합니다. 팩토리 함수는 원하는 결과형과 함수의 인자형들로 호출되어야 하며, 데코레이터 팩토리로 사용되어 @wrapper 문법을 통해 함수에 적용될 수 있습니다. 예제는 콜백 함수를 참조하십시오.

ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)

반환된 함수 프로토타입은 표준 C 호출 규칙을 사용하는 함수를 만듭니다. 이 함수는 호출 중에 GIL을 해제합니다. use_errno를 참으로 설정하면, 시스템 errno 변수의 ctypes 내부 복사본이 호출 전후에 실제 errno 값과 교환됩니다; use_last_error는 윈도우 에러 코드에 대해 같은 일을 합니다.

ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)

반환된 함수 프로토타입은 stdcall 호출 규약을 사용하는 함수를 생성합니다. 이 함수는 호출 중에 GIL을 해제합니다. use_errnouse_last_error 는 위의 것과 동일한 의미입니다.

가용성: Windows

ctypes.PYFUNCTYPE(restype, *argtypes)

반환된 함수 프로토타입은 파이썬 호출 규칙을 사용하는 함수를 만듭니다. 이 함수는 호출 도중 GIL을 해제하지 않습니다.

이러한 팩토리 함수로 만들어진 함수 프로토타입은 호출의 매개 변수 형과 수에 따라 다른 방법으로 인스턴스를 만들 수 있습니다:

prototype(address)

지정된 정수 주소에 있는 외부 함수를 반환합니다.

prototype(callable)

파이썬 callable로 C 호출 가능 함수(콜백 함수)를 만듭니다.

prototype(func_spec[, paramflags])

공유 라이브러리가 내보낸 외부 함수를 반환합니다. func_spec은 2-튜플 (name_or_ordinal, library) 여야 합니다. 첫 번째 항목은 내보낸 함수의 문자열 이름이거나, 작은 정수로 표현된 내보낸 함수의 서수(ordinal)입니다. 두 번째 항목은 공유 라이브러리 인스턴스입니다.

prototype(vtbl_index, name[, paramflags[, iid]])

COM 메서드를 호출할 외부 함수를 반환합니다. vtbl_index는 가상 함수 테이블에 대한 인덱스이며, 작은 음이 아닌 정수입니다. name은 COM 메서드의 이름입니다. iid는 확장 에러 보고에 사용되는 인터페이스 식별자를 가리키는 선택적 포인터입니다.

iid 가 지정되지 않으면, COM 메서드 호출에 실패했을 경우 OSError 이 발생합니다. iid 가 지정된 경우에는 대신 COMError 이 발생합니다.

COM 메서드는 특별한 호출 규약(calling convention)을 사용합니다. 이는 argtypes 튜플에 지정된 매개변수 외에도 COM 인터페이스 포인터가 첫 번째 인자로 필요함을 의미합니다.

가용성: Windows

선택적 paramflags 매개 변수는 위에 설명된 기능보다 훨씬 많은 기능을 갖는 외부 함수 래퍼를 만듭니다.

paramflagsargtypes 와 길이가 같은 튜플이어야 합니다.

이 튜플의 각 항목에는 매개 변수에 대한 추가 정보가 들어 있으며, 한 개, 두 개 또는 세 개의 항목이 들어있는 튜플이어야 합니다.

첫 번째 항목은 매개 변수의 방향 플래그 조합을 포함하는 정수입니다:

1

함수에 대한 입력 매개 변수를 지정합니다.

2

출력 매개 변수. 외부 함수가 값을 채웁니다.

4

기본값이 정수 0인 입력 매개 변수.

선택적인 두 번째 항목은 문자열 매개 변수 이름입니다. 이것이 지정되면, 이름있는 매개 변수로 외부 함수를 호출할 수 있습니다.

선택적 세 번째 항목은 이 매개 변수의 기본값입니다.

다음 예제는 Windows의 MessageBoxW 함수를 기본 매개변수와 명명된 인자를 지원하도록 래핑하는 방법을 보여줍니다. Windows 헤더 파일からの C 선언은 다음과 같습니다:

WINUSERAPI int WINAPI
MessageBoxW(
    HWND hWnd,
    LPCWSTR lpText,
    LPCWSTR lpCaption,
    UINT uType);

:mod:`!ctypes`을 사용하여 래핑하는 방법이 여기 나와 있습니다:

>>> from ctypes import c_int, WINFUNCTYPE, windll
>>> from ctypes.wintypes import HWND, LPCWSTR, UINT
>>> prototype = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)
>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", "Hello from ctypes"), (1, "flags", 0)
>>> MessageBox = prototype(("MessageBoxW", windll.user32), paramflags)

이제 MessageBox 외부 함수를 다음과 같이 호출할 수 있습니다.:

>>> MessageBox()
>>> MessageBox(text="Spam, spam, spam")
>>> MessageBox(flags=2, text="foo bar")

두 번째 예제는 출력 매개 변수를 보여줍니다. win32 GetWindowRect 함수는 지정된 창의 크기를 조회하는데, 호출자가 제공해야 하는 RECT 구조체로 복사합니다. 다음은 C 선언입니다:

WINUSERAPI BOOL WINAPI
GetWindowRect(
     HWND hWnd,
     LPRECT lpRect);

:mod:`!ctypes`을 사용하여 래핑하는 방법이 여기 나와 있습니다:

>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError
>>> from ctypes.wintypes import BOOL, HWND, RECT
>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
>>> paramflags = (1, "hwnd"), (2, "lprect")
>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
>>>

출력 매개 변수가 있는 함수는, 하나뿐이면 자동으로 출력 매개 변숫값을 반환하고, 여러 개면 출력 매개 변숫값을 포함하는 튜플을 반환하므로, GetWindowRect 함수는 이제 호출되면 RECT 인스턴스를 반환합니다.

출력 매개변수는 errcheck 프로토콜과 결합하여 추가적인 출력 처리 및 오류 확인을 수행할 수 있습니다. win32 GetWindowRect API 함수는 성공 또는 실패를 알리기 위해 BOOL 을 반환하므로, 이 함수는 오류 확인을 수행하고 API 호출이 실패한 경우 예외를 발생시킬 수 있습니다:

>>> def errcheck(result, func, args):
...     if not result:
...         raise WinError()
...     return args
...
>>> GetWindowRect.errcheck = errcheck
>>>

만약 errcheck 함수가 받은 인자 튜플을 변경하지 않고 반환하는 경우, ctypes`은 출력 매개변수에 대해 정상적인 처리를 계속합니다. 만약 `RECT 인스턴스 대신 창 좌표의 튜플을 반환하고 싶다면, 함수 내에서 필드를 검색하여 이를 반환할 수 있습니다. 그렇게 하면 정상적인 처리는 더 이상 일어나지 않습니다:

>>> def errcheck(result, func, args):
...     if not result:
...         raise WinError()
...     rc = args[1]
...     return rc.left, rc.top, rc.bottom, rc.right
...
>>> GetWindowRect.errcheck = errcheck
>>>

유틸리티 함수

ctypes.addressof(obj)

메모리 버퍼의 주소를 정수로 반환합니다. obj는 ctypes 형의 인스턴스여야 합니다.

인자 obj감사 이벤트 ctypes.addressof를 발생시킵니다.

ctypes.alignment(obj_or_type)

ctypes 형의 정렬 요구 사항을 반환합니다. obj_or_type는 ctypes 형이나 인스턴스여야 합니다.

ctypes.byref(obj[, offset])

obj에 대한 경량 포인터를 반환합니다. obj는 ctypes 형의 인스턴스여야 합니다. offset의 기본값은 0이며, 내부 포인터 값에 더해질 정수여야 합니다.

byref(obj, offset)는 이 C 코드에 해당합니다:

(((char *)&obj) + offset)

반환된 객체는 외부 함수 호출 매개 변수로만 사용할 수 있습니다. pointer(obj)와 비슷하게 동작하지만, 훨씬 빨리 만들어집니다.

ctypes.CopyComPointer(src, dst)

src 에서 dst 로 COM 포인터를 복사하고 Windows 전용 HRESULT 값을 반환합니다.

srcNULL 이 아니면, AddRef 메서드가 호출되어 참조 횟수가 증가합니다.

대조적으로, dst 는 새 값을 할당하기 전에 참조 횟수가 감소하지 않습니다. dstNULL 이 아닌 한, 호출자가 필요할 때 Release 메서드를 호출하여 참조 횟수를 감소시킬 책임이 있습니다.

가용성: Windows

Added in version 3.14.

ctypes.cast(obj, type)

이 함수는 C의 형 변환 연산자와 유사합니다. obj와 같은 메모리 블록을 가리키는 type 형의 새 인스턴스를 반환합니다. type은 포인터형이어야 하며, obj는 포인터로 해석될 수 있는 객체여야 합니다.

ctypes.create_string_buffer(init, size=None)
ctypes.create_string_buffer(size)

이 함수는 가변 문자 버퍼를 만듭니다. 반환된 객체는 c_char의 ctypes 배열입니다.

만약 size 가 주어지면 (그리고 None 이 아니라면), 이는 int 이어야 합니다. 이는 반환된 배열의 크기를 지정합니다.

만약 init 인자가 주어진다면, 이는 :class:`bytes`여야 합니다. 이 값은 배열 항목을 초기화하는 데 사용됩니다. 이렇게 초기화되지 않은 바이트는 0(NUL)으로 설정됩니다.

size 가 지정되지 않았거나 None 인 경우, 버퍼는 init 보다 하나의 요소가 더 커지며, 사실상 NUL 종료 문자를 추가하는 것입니다.

두 인자 모두 제공되는 경우, sizelen(init) 미만일 수 없습니다.

경고

sizelen(init) 과 같으면 NUL 종료 문자는 추가되지 않습니다. 이러한 버퍼를 C 문자열로 취급하지 마십시오.

예를 들면:

>>> bytes(create_string_buffer(2))
b'\x00\x00'
>>> bytes(create_string_buffer(b'ab'))
b'ab\x00'
>>> bytes(create_string_buffer(b'ab', 2))
b'ab'
>>> bytes(create_string_buffer(b'ab', 4))
b'ab\x00\x00'
>>> bytes(create_string_buffer(b'abcdef', 2))
Traceback (most recent call last):
   ...
ValueError: byte string too long

init, size 인자로 감사 이벤트 ctypes.create_string_buffer를 발생시킵니다.

ctypes.create_unicode_buffer(init, size=None)
ctypes.create_unicode_buffer(size)

이 함수는 가변 유니코드 문자 버퍼를 만듭니다. 반환된 객체는 c_wchar의 ctypes 배열입니다.

이 함수는 create_string_buffer() 와 동일한 인자를 받지만, init 은 문자열이어야 하고 sizec_wchar 를 세어집니다.

init, size 인자로 감사 이벤트 ctypes.create_unicode_buffer를 발생시킵니다.

ctypes.DllCanUnloadNow()

이 함수는 ctypes를 사용하여 프로세스 내 COM 서버를 구현할 수 있게 해주는 훅(hook)입니다. _ctypes 확장 DLL이 외보내는 DllCanUnloadNow 함수에서 호출됩니다.

가용성: Windows

ctypes.DllGetClassObject()

이 함수는 ctypes를 사용하여 프로세스 내 COM 서버를 구현할 수 있게 해주는 훅(hook)입니다. _ctypes 확장 DLL이 외보내는 DllGetClassObject 함수에서 호출됩니다.

가용성: Windows

ctypes.util.dllist()

현재 프로세스에 로드된 공유 라이브러리 경로 목록을 제공해 보십시오. 이 경로는 어떤 방식으로도 정규화되거나 처리되지 않습니다. 기본 플랫폼 API가 실패하는 경우, 이 함수는 :exc:`OSError`를 발생시킬 수 있습니다. 정확한 기능은 시스템 의존적입니다.

대부분의 플랫폼에서 목록의 첫 번째 요소는 현재 실행 가능한 파일을 나타냅니다. 빈 문자열일 수도 있습니다.

가용성: Windows, macOS, iOS, glibc, BSD libc, musl

Added in version 3.14.

ctypes.FormatError([code])

오류 코드 code 에 대한 텍스트 설명을 반환합니다. 오류 코드가 지정되지 않은 경우, Windows API 함수 GetLastError() 를 호출하여 마지막 오류 코드를 사용합니다.

가용성: Windows

ctypes.GetLastError()

호출하는 스레드에서 Windows가 설정한 마지막 오류 코드를 반환합니다. 이 함수는 Windows GetLastError() 함수를 직접 호출하며, 오류 코드의 ctypes 내부 복사본을 반환하지 않습니다.

가용성: Windows

ctypes.get_errno()

호출하는 스레드에서 시스템 errno 변수의 ctypes 내부 복사본의 현재 값을 반환합니다.

인자 없이 감사 이벤트 ctypes.get_errno를 발생시킵니다.

ctypes.get_last_error()

호출하는 스레드에서 시스템 LastError 변수의 ctypes 내부 복사본의 현재 값을 반환합니다.

가용성: Windows

인자 없이 감사 이벤트 ctypes.get_last_error를 발생시킵니다.

ctypes.memmove(dst, src, count)

표준 C memmove 라이브러리 함수와 같습니다: count 바이트를 src에서 dst로 복사합니다. dstsrc는 정수이거나 포인터로 변환할 수 있는 ctypes 인스턴스여야 합니다.

ctypes.memset(dst, c, count)

표준 C memset 라이브러리 함수와 같습니다: 주소 dst의 메모리 블록을 값 ccount 바이트로 채웁니다. dst는 주소를 지정하는 정수거나 ctypes 인스턴스여야 합니다.

ctypes.POINTER(type, /)

ctypes 포인터 타입을 생성하거나 반환합니다. 포인터 타입은 내부적으로 캐싱되고 재사용되므로, 이 함수를 반복해서 호출하는 것은 저렴합니다(cheap). type*은 ctypes 타입을 *반드시 입력해야 합니다.

결과로 얻는 포인터 타입은 type__pointer_type__ 속성에 캐시됩니다. 첫 번째 POINTER 호출 이전에 이 속성을 설정하여 사용자 정의 포인터 타입을 설정하는 것이 가능합니다. 그러나 이렇게 하는 것은 권장되지 않습니다. 적절한 포인터 타입을 수동으로 생성하는 것은 미래 파이썬 버전에서 변경될 수 있는 구현 세부 사항에 의존하지 않고는 어렵기 때문입니다.

ctypes.pointer(obj, /)

obj 를 가리키는 새 포인터 인스턴스를 생성합니다. 반환된 객체는 POINTER(type(obj)) 타입입니다.

참고 사항: 객체에 대한 포인터를 단지 외부 함수 호출로 전달하려면 훨씬 빠른 byref(obj)를 사용해야 합니다.

ctypes.resize(obj, size)

이 함수는 obj의 내부 메모리 버퍼의 크기를 조정합니다. obj는 ctypes 형의 인스턴스여야 합니다. sizeof(type(obj))로 주어지는 객체 형의 원래 크기보다 버퍼를 작게 만들 수는 없지만, 버퍼를 확대할 수 있습니다.

ctypes.set_errno(value)

호출 중인 스레드의 시스템 errno 변수의 ctypes 내부 복사본의 현재 값을 value로 설정하고 이전 값을 반환합니다.

인자 errno감사 이벤트 ctypes.set_errno를 발생시킵니다.

ctypes.set_last_error(value)

호출하는 스레드에서 시스템 LastError 변수의 ctypes 내부 복사본의 현재 값을 value 로 설정하고 이전 값을 반환합니다.

가용성: Windows

인자 error감사 이벤트 ctypes.set_last_error를 발생시킵니다.

ctypes.sizeof(obj_or_type)

ctypes 형이나 인스턴스 메모리 버퍼의 크기를 바이트 단위로 반환합니다. C sizeof 연산자와 같은 일을 합니다.

ctypes.string_at(ptr, size=-1)

void *ptr 에 있는 바이트 문자열을 반환합니다. size 가 지정된 경우, 이는 크기로 사용되며 그렇지 않은 경우 문자열은 NULL 종료 문자열로 가정됩니다.

인자 ptrsize 를 사용하여 감사 이벤트 ctypes.string_at 을 발생시킵니다.

ctypes.WinError(code=None, descr=None)

OSError 의 인스턴스를 생성합니다. code 가 지정되지 않은 경우, 오류 코드를 결정하기 위해 GetLastError() 가 호출됩니다. descr 이 지정되지 않은 경우, FormatError() 가 호출되어 오류에 대한 텍스트 설명을 가져옵니다.

가용성: Windows

버전 3.3에서 변경: 과거에는 생성되던 WindowsError 인스턴스가 현재는 :exc:`OSError`의 별칭입니다.

ctypes.wstring_at(ptr, size=-1)

void *ptr 에 있는 와이드 문자열을 반환합니다. size 가 지정된 경우, 이는 문자열의 문자로 사용되며 그렇지 않은 경우 문자열은 NULL 종료 문자로 가정됩니다.

인자 ptrsize 를 사용하여 감사 이벤트 ctypes.wstring_at 을 발생시킵니다.

ctypes.memoryview_at(ptr, size, readonly=False)

void *ptr 에서 시작하는 메모리를 참조하는 길이 sizememoryview 객체를 반환합니다.

readonly 가 true이면, 반환된 memoryview 객체는 기본 메모리를 수정하는 데 사용될 수 없습니다. (다른 수단으로 변경된 내용은 여전히 반환된 객체에 반영됩니다.)

This function is similar to string_at() with the key difference of not making a copy of the specified memory. It is a semantically equivalent (but more efficient) alternative to memoryview((c_byte * size).from_address(ptr)). (While from_address() only takes integers, ptr can also be given as a ctypes.POINTER or a byref() object.)

인자 address, size, readonly\으로 감사 이벤트 ctypes.memoryview_at\를 발생시킵니다.

Added in version 3.14.

데이터형

class ctypes._CData

이 비공개 클래스는 모든 ctypes 데이터형의 공통 베이스 클래스입니다. 무엇보다도, 모든 ctypes 형 인스턴스에는 C 호환 데이터를 보관하는 메모리 블록이 포함됩니다; 메모리 블록의 주소는 addressof() 도우미 함수에 의해 반환됩니다. 다른 인스턴스 변수는 _objects로 노출됩니다; 여기에는 메모리 블록에 포인터가 포함되어있을 때, 살려둘 필요가 있는 다른 파이썬 객체가 포함되어 있습니다.

ctypes 데이터형의 공통 메서드, 이것들은 모두 클래스 메서드입니다 (정확히 말하면, 메타 클래스의 메서드입니다):

from_buffer(source[, offset])

이 메서드는 source 객체의 버퍼를 공유하는 ctypes 인스턴스를 반환합니다. source 객체는 쓰기 가능한 버퍼 인터페이스를 지원해야 합니다. 선택적 offset 매개 변수는 source 버퍼의 오프셋을 바이트 단위로 지정합니다; 기본값은 0입니다. source 버퍼가 충분히 크지 않으면 ValueError가 발생합니다.

인자 pointer, size, offset으로 감사 이벤트 ctypes.cdata/buffer를 발생시킵니다.

from_buffer_copy(source[, offset])

이 메서드는 읽을 수 있어야 하는 source 객체 버퍼에서 버퍼를 복사하여 ctypes 인스턴스를 만듭니다. 선택적 offset 매개 변수는 원본 버퍼의 오프셋을 바이트 단위로 지정합니다. 기본값은 0입니다. 소스 버퍼가 충분히 크지 않으면 ValueError가 발생합니다.

인자 pointer, size, offset으로 감사 이벤트 ctypes.cdata/buffer를 발생시킵니다.

from_address(address)

이 메서드는 정수 address로 지정된 메모리를 사용하여 ctypes 형 인스턴스를 반환합니다.

이 메서드와 이 메서드를 간접적으로 호출하는 다른 것들은 인자 address감사 이벤트 ctypes.cdata를 발생시킵니다.

from_param(obj)

이 메서드는 *obj*`를 ctypes 타입에 맞춥니다. 이 함수는 외래 함수 호출에서 실제 사용된 객체가, 해당 유형이 외래 함수의 :attr:`~_CFuncPtr.argtypes 튜플에 존재하는 경우에 호출됩니다; 이는 함수 호출 매개변수로 사용될 수 있는 객체를 반환해야 합니다.

모든 ctypes 데이터형은 이 클래스 메서드의 기본 구현을 갖는데, obj 가 이 형의 인스턴스면 obj 를 반환합니다. 일부 형은 다른 객체도 허용합니다.

in_dll(library, name)

이 메서드는 공유 라이브러리가 내보낸 ctypes 형 인스턴스를 반환합니다. name은 데이터를 내보내는 심볼의 이름이고, library는 로드된 공유 라이브러리입니다.

ctypes 데이터형의 공통 클래스 변수:

__pointer_type__

해당 ctypes 데이터 유형에 대해 :func:`POINTER`를 호출하여 생성된 포인터 타입입니다. 포인터 타입이 아직 생성되지 않았다면 해당 어트리뷰트는 존재하지 않습니다.

Added in version 3.14.

ctypes 데이터형의 공통 인스턴스 변수:

_b_base_

때로 ctypes 데이터 인스턴스는 포함하는 메모리 블록을 소유하지 않고, 베이스 객체의 메모리 블록의 일부를 공유합니다. _b_base_ 읽기 전용 멤버는 메모리 블록을 소유한 루트 ctypes 객체입니다.

_b_needsfree_

이 읽기 전용 변수는 ctypes 데이터 인스턴스가 메모리 블록을 스스로 할당했을 때 참이고, 그렇지 않으면 거짓입니다.

_objects

이 멤버는 None 이거나 메모리 블록 내용이 계속 유효하도록 유지되어야 하는 파이썬 객체를 포함하는 딕셔너리입니다. 이 객체는 디버깅을 위해서만 노출됩니다; 이 딕셔너리의 내용을 수정하지 마십시오.

기본 데이터형

class ctypes._SimpleCData

이 비공개 클래스는 모든 기본 ctypes 데이터형의 베이스 클래스입니다. 여기에는 기본 ctypes 데이터형의 공통 어트리뷰트가 들어 있으므로 여기에서 언급합니다. _SimpleCData_CData의 서브 클래스이므로, 메서드와 어트리뷰트를 상속받습니다. 포인터가 아니고 포인터를 포함하지 않는 ctypes 데이터형을 이제 피클 할 수 있습니다.

인스턴스에는 어트리뷰트가 하나 있습니다:

value

이 어트리뷰트는 인스턴스의 실제 값을 포함합니다. 정수형과 포인터형에서는 정수고, 문자형에서는 단일 문자 바이트열 객체나 문자열이고, 문자 포인터형에서는 파이썬 바이트열 객체나 문자열입니다.

ctypes 인스턴스에서 value 어트리뷰트를 조회하면, 일반적으로 매번 새 객체가 반환됩니다. ctypes\는 원래의 객체 반환을 구현하지 않습니다. 항상 새로운 객체가 구성됩니다. 다른 모든 ctypes 객체 인스턴스에서도 동일합니다.

각 서브클래스는 클래스 어트리뷰트를 가집니다:

_type_

내부 타입 코드를 문자열로 포함하는 클래스 어트리뷰트입니다. 요약 정보는 :ref:`ctypes-fundamental-data-types`를 참조하십시오.

요약에서 *로 표시된 유형은 다른 _SimpleCData 서브클래스의 별칭이거나(또는 항상)일 수 있으며, 반드시 나열된 타입 코드를 사용하지 않을 수 있습니다. 예를 들어, 플랫폼의 long, long longtime_t C 타입이 동일하다면, c_long, c_longlongc_time_t 모두 단일 클래스인 c_long`을 참조하며, 이의 :attr:`_type_ 코드는 'l'``입니다. ``'L' 코드는 사용되지 않습니다.

더 보기

array`와 :ref:`struct 모듈, 그리고 numpy <https://numpy.org/doc/stable/reference/arrays.interface.html#object.__array_interface__>\ 같은 타사 모듈은 유사하지만 약간 다른 타입 코드를 사용합니다.

기본 데이터 유형들은 외래 함수 호출 결과로 반환되거나, 구조체 필드 멤버를 조회하거나 배열 항목을 조회하는 경우 등에는 네이티브 Python 타입으로 투명하게 변환됩니다. 즉, 외래 함수에 restype`가 :class:`c_char_p`인 경우, 언제나 Python bytes 객체를 받게 되며 *never* :class:`c_char_p 인스턴스를 받지 않습니다.

기본 데이터 유형의 서브클래스는 이러한 동작을 상속받지 않습니다. 따라서 외래 함수의 restype`가 :class:`c_void_p`의 서브클래스인 경우, 함수 호출로부터 서브클래스의 인스턴스를 받게 됩니다. 물론 ``value` 어트리뷰트를 액세스하여 포인터 값을 얻을 수 있습니다.

다음은 기본 ctypes 데이터형입니다:

class ctypes.c_byte

Represents the C signed char datatype, and interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_char

C char 데이터형을 나타내고, 값을 단일 문자로 해석합니다. 생성자는 선택적 문자열 초기화자를 받으며, 문자열의 길이는 정확히 한 문자여야 합니다.

class ctypes.c_char_p

Represents the C char* datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, POINTER(c_char) must be used. The constructor accepts an integer address, or a bytes object.

class ctypes.c_double

C double 데이터형을 나타냅니다. 생성자는 선택적 float 초기화자를 받습니다.

class ctypes.c_longdouble

Represents the C long double datatype. The constructor accepts an optional float initializer. On platforms where sizeof(long double) == sizeof(double) it is an alias to c_double.

class ctypes.c_float

C float 데이터형을 나타냅니다. 생성자는 선택적 float 초기화자를 받습니다.

class ctypes.c_double_complex

사용 가능한 경우 C double complex 데이터형을 나타냅니다. 생성자는 선택적 complex 초기화자를 받습니다.

Added in version 3.14.

class ctypes.c_float_complex

사용 가능한 경우 C float complex 데이터형을 나타냅니다. 생성자는 선택적 complex 초기화자를 받습니다.

Added in version 3.14.

class ctypes.c_longdouble_complex

사용 가능한 경우 C long double complex 데이터형을 나타냅니다. 생성자는 선택적 complex 초기화자를 받습니다.

Added in version 3.14.

class ctypes.c_int

Represents the C signed int datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where sizeof(int) == sizeof(long) it is an alias to c_long.

class ctypes.c_int8

C signed int 데이터형을 나타냅니다. 이는 :class:`c_byte`의 또 다른 이름입니다.

class ctypes.c_int16

C signed int 데이터형을 나타냅니다. 보통은 :class:`c_short`의 별칭입니다.

class ctypes.c_int32

C signed int 데이터형을 나타냅니다. 보통은 :class:`c_int`의 별칭입니다.

class ctypes.c_int64

C signed int 데이터형을 나타냅니다. 보통은 :class:`c_longlong`의 별칭입니다.

class ctypes.c_long

C signed long 데이터형을 나타냅니다. 생성자는 선택적 정수 초기화자를 받으며, 오버플로우 검사는 수행하지 않습니다.

class ctypes.c_longlong

Represents the C signed long long datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where sizeof(long long) == sizeof(long) it is an alias to c_long.

class ctypes.c_short

C signed short 데이터형을 나타냅니다. 생성자는 선택적 정수 초기화자를 받으며, 오버플로우 검사는 수행하지 않습니다.

class ctypes.c_size_t

C size_t 데이터형을 나타냅니다. 보통 다른 부호 없는 정수형의 별칭입니다.

class ctypes.c_ssize_t

Py_ssize_t 데이터형을 나타냅니다. 이는 size_t 의 부호 있는 버전이며, 즉 POSIX ssize_t 타입입니다. 보통 다른 정수형의 별칭입니다.

Added in version 3.2.

class ctypes.c_time_t

C time_t 데이터형을 나타냅니다. 보통 다른 정수형의 별칭입니다.

Added in version 3.12.

class ctypes.c_ubyte

C unsigned char 데이터형을 나타내며, 값을 작은 정수로 해석합니다. 생성자는 선택적 정수 초기화자를 받으며, 오버플로우 검사는 수행하지 않습니다.

class ctypes.c_uint

Represents the C unsigned int datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where sizeof(int) == sizeof(long) it is an alias for c_ulong.

class ctypes.c_uint8

C 8비트 unsigned int 데이터형을 나타냅니다. 이는 :class:`c_ubyte`의 별칭입니다.

class ctypes.c_uint16

C 16비트 unsigned int 데이터형을 나타냅니다. 보통은 :class:`c_ushort`의 별칭입니다.

class ctypes.c_uint32

C 32비트 unsigned int 데이터형을 나타냅니다. 보통은 :class:`c_uint`의 별칭입니다.

class ctypes.c_uint64

C 64비트 unsigned int 데이터형을 나타냅니다. 보통은 :class:`c_ulonglong`의 별칭입니다.

class ctypes.c_ulong

C unsigned long 데이터형을 나타냅니다. 생성자는 선택적 정수 초기화자를 받으며, 오버플로우 검사는 수행하지 않습니다.

class ctypes.c_ulonglong

Represents the C unsigned long long datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where sizeof(long long) == sizeof(long) it is an alias to c_long.

class ctypes.c_ushort

C unsigned short 데이터형을 나타냅니다. 생성자는 선택적 정수 초기화자를 받으며, 오버플로우 검사는 수행하지 않습니다.

class ctypes.c_void_p

C void* 타입을 나타냅니다. 값은 정수로 표현됩니다. 생성자는 선택적 정수 초기화자를 받습니다.

class ctypes.c_wchar

C wchar_t 데이터형을 나타내고, 값을 단일 문자 유니코드 문자열로 해석합니다. 생성자는 선택적 문자열 초기화자를 받아들입니다, 문자열의 길이는 정확히 한 문자여야 합니다.

class ctypes.c_wchar_p

C wchar_t* 데이터형을 나타내며, 이는 NULL로 끝나는 와이드 문자열에 대한 포인터여야 합니다. 생성자는 정수 주소 또는 문자열을 받습니다.

class ctypes.c_bool

C bool 데이터형(_Bool (C99)이 더 정확합니다) 을 나타냅니다. 값은 True 또는 False 일 수 있으며, 생성자는 진리값을 가진 모든 객체를 받습니다.

class ctypes.HRESULT

함수 또는 메서드 호출에 대한 성공 또는 오류 정보를 담고 있는 HRESULT 값을 나타냅니다.

가용성: Windows

class ctypes.py_object

C PyObject* 데이터형을 나타냅니다. 인자 없이 호출하면 NULL PyObject* 포인터를 생성합니다.

버전 3.14에서 변경: :class:`!py_object`는 이제 :term:`일반 타입 <generic type>`입니다.

ctypes.wintypes 모듈은 HWND, WPARAM, VARIANT_BOOL 또는 DWORD`와 같이 상당히 많은 다른 Windows 전용 데이터 타입을 제공합니다. :c:type:!MSG`나 RECT 같은 유용한 구조체도 정의되어 있습니다.

구조화된 데이터형

class ctypes.Union(*args, **kw)

네이티브 바이트 순서의 공용체를 위한 추상 베이스 클래스.

공용체는 구조체와 공통 속성과 동작을 공유합니다. 자세한 내용은 Structure 문서를 참조하세요.

class ctypes.BigEndianUnion(*args, **kw)

빅 엔디안(big endian) 바이트 순서의 공용체를 위한 추상 베이스 클래스입니다.

Added in version 3.11.

class ctypes.LittleEndianUnion(*args, **kw)

리틀 엔디안(little endian) 바이트 순서의 공용체를 위한 추상 베이스 클래스입니다.

Added in version 3.11.

class ctypes.BigEndianStructure(*args, **kw)

빅엔디안(big endian) 바이트 순서의 구조체를 위한 추상 베이스 클래스.

class ctypes.LittleEndianStructure(*args, **kw)

리틀엔디안(little endian) 바이트 순서로의 구조체를 위한 추상 베이스 클래스.

비네이티브 바이트 순서를 가진 구조체와 공용체에는 포인터 타입 필드나 포인터 타입 필드를 포함하는 다른 데이터 타입을 포함할 수 없습니다.

class ctypes.Structure(*args, **kw)

네이티브 바이트 순서의 구조체를 위한 추상 베이스 클래스.

구상 구조체와 공용체 형은 이 형 중 하나를 서브 클래싱하고 적어도 _fields_ 클래스 변수를 정의해서 만들어야 합니다. ctypes\는 직접 어트리뷰트 액세스로 필드를 읽고 쓸 수 있는 디스크립터\를 만듭니다. 이것들은

_fields_

구조체 필드를 정의하는 시퀀스. 항목은 2-튜플이나 3-튜플이어야 합니다. 첫 번째 항목은 필드의 이름이고, 두 번째 항목은 필드의 형을 지정합니다; 모든 ctypes 데이터형이 될 수 있습니다.

c_int와 같은 정수형 필드에서는, 세 번째 선택적 항목을 지정할 수 있습니다. 필드의 비트 폭을 정의하는 작은 양의 정수여야 합니다.

필드 이름은 하나의 구조체나 공용체 내에서 고유해야 합니다. 이것은 검사되지 않습니다, 이름이 중복되면 하나의 필드만 액세스할 수 있습니다.

_fields_ 클래스 변수를, Structure 서브 클래스를 정의하는 클래스 문 뒤에서 정의할 수 있습니다. 직접 또는 간접적으로 자신을 참조하는 데이터형을 만들 수 있게 합니다:

class List(Structure):
    pass
List._fields_ = [("pnext", POINTER(List)),
                 ...
                ]

_fields_ 클래스 변수는 단 한 번만 설정할 수 있습니다. 이후 할당은 AttributeError\를 발생시킵니다.

또한, _fields_ 클래스 변수는 구조체나 공용체 형이 처음 사용되기 전에 정의되어야 합니다. 즉 인스턴스나 서브 클래스가 생성되거나, on 그것에 sizeof`가 호출되는 등의 경우입니다. 이후의 :attr:()!_fields_` 할당은 AttributeError\를 발생시킵니다. 만약 그러한 사용 전에 _fields_`가 설정되지 않았다면, 구조체나 공용체는 마치 :attr:!_fields_`가 비어 있는 것처럼 자체 필드가 없습니다.

구조체 형의 서브-서브 클래스는 베이스 클래스의 필드와, 만약 있다면 서브-서브 클래스에 정의된 :attr:`_fields_`를 상속합니다.

_pack_

인스턴스에서 구조체 필드의 정렬을 재정의할 수 있는 선택적 작은 정수입니다.

이것은 MSVC와 호환되는 메모리 레이아웃에 대해서만 구현되어 있습니다 (참조: _layout_).

_pack_ 를 0으로 설정하는 것은 아예 설정하지 않은 것과 같습니다. 그렇지 않으면, 값은 양의 2의 거듭제곱이어야 합니다. 효과는 C의 #pragma pack(N) 와 동일하지만, ctypes 는 컴파일러가 허용하는 것보다 더 큰 n 값을 허용할 수 있습니다.

_pack_ must already be defined when _fields_ is assigned, otherwise it will have no effect.

버전 3.14에서 폐지되었고, 버전 3.19에서 제거됩니다: 역사적인 이유로, 만약 _pack_ 가 0이 아니면 기본적으로 MSVC와 호환되는 레이아웃이 사용됩니다. 비(非) Windows 플랫폼에서 이 기본값은 더 이상 권장되지 않으며 Python 3.19부터 오류가 될 예정입니다. 의도하는 경우, _layout_'ms' 로 명시적으로 설정하십시오.

_align_

패킹하거나 메모리로부터 언패킹할 때 구조체의 정렬을 증가시키는 데 사용할 수 있는 선택적 작은 정수입니다.

값은 음수가 아니어야 합니다. 효과는 GCC의 __attribute__((aligned(N))) 나 MSVC의 #pragma align(N) 와 동일하지만, ctypes 는 컴파일러가 거부할 값을 허용할 수 있습니다.

_align_ 는 구조체의 정렬 요구 사항을 증가 시킬 수만 있습니다. 이를 0 또는 1로 설정하는 것은 효과가 없습니다.

2의 거듭제곱이 아닌 값을 사용하는 것은 권장되지 않으며 예상치 못한 동작을 유발할 수 있습니다.

_align_ must already be defined when _fields_ is assigned, otherwise it will have no effect.

Added in version 3.13.

_layout_

구조체/공용체 레이블을 지정하는 선택적 문자열입니다. 현재 다음과 같이 설정할 수 있습니다:

  • "ms_": Microsoft 컴파일러(MSVC)에서 사용되는 레이아웃입니다. GCC 및 Clang에서는 __attribute__((ms_struct)) 로 이 레이아웃을 선택할 수 있습니다.

  • "gcc-sysv": Linux와 macOS에서 사용되는 System V 또는 “SysV 유사” 데이터 모델을 사용하는 GCC의 레이아웃입니다. 이 레이아웃에서는 :attr:`~Structure._pack_`가 unset이거나 0이어야 합니다.

명시적으로 설정하지 않은 경우, ctypes 는 플랫폼의 관례와 일치하는 기본값을 사용합니다. 이 기본값은 향후 Python 릴리스에서 변경될 수 있습니다(예: 새로운 플랫폼이 공식 지원을 받거나 유사한 플랫폼 간에 차이가 발견되는 경우). 현재 기본값은 다음과 같습니다:

  • Windows의 경우: "ms"

  • _pack_`가 지정된 경우: `”ms”`` (이는 폐기되었습니다. _pack_ 문서를 참조하십시오.)

  • 그 외의 경우: "gcc-sysv"

:attr:`!_layout_`는 :attr:`~Structure._fields_`가 할당되기 전에 이미 정의되어 있어야 합니다. 그렇지 않으면 아무 효과가 없습니다.

Added in version 3.14.

_anonymous_

이름 없는(익명) 필드의 이름을 나열하는 선택적 시퀀스. _fields_가 대입될 때 _anonymous_는 이미 정의되어 있어야 합니다. 그렇지 않으면 아무 효과가 없습니다.

이 변수에 나열된 필드는 구조체 또는 공용체 형 필드여야 합니다. ctypes\는 구조체나 공용체 필드를 만들 필요 없이, 중첩된 필드에 직접 액세스할 수 있는 디스크립터를 구조체 형에 만듭니다.

다음은 예제 형입니다 (윈도우):

class _U(Union):
    _fields_ = [("lptdesc", POINTER(TYPEDESC)),
                ("lpadesc", POINTER(ARRAYDESC)),
                ("hreftype", HREFTYPE)]

class TYPEDESC(Structure):
    _anonymous_ = ("u",)
    _fields_ = [("u", _U),
                ("vt", VARTYPE)]

TYPEDESC 구조체는 COM 데이터형을 설명합니다. vt 필드는 공용체 필드 중 어느 것이 유효한지 지정합니다. u 필드가 익명 필드로 정의되었으므로, 이제 TYPEDESC 인스턴스에서 멤버에 직접 액세스할 수 있습니다. td.lptdesctd.u.lptdesc는 동등하지만, 앞에 있는 것이 임시 공용체 인스턴스를 만들 필요가 없으므로 더 빠릅니다:

td = TYPEDESC()
td.vt = VT_PTR
td.lptdesc = POINTER(some_type)
td.u.lptdesc = POINTER(some_type)

구조체 형의 서브-서브 클래스를 정의할 수 있으며, 베이스 클래스의 필드를 상속합니다. 서브 클래스 정의에 별도의 _fields_ 변수가 있으면, 여기에 지정된 필드가 베이스 클래스의 필드에 추가됩니다.

구조체와 공용체 생성자는 위치와 키워드 인자를 모두 받아들입니다. 위치 인자는 _fields_에 나타나는 순서대로 멤버 필드를 초기화하는 데 사용됩니다. 생성자의 키워드 인자는 어트리뷰트 대입으로 해석되므로, _fields_를 같은 이름으로 초기화하거나, _fields_에 없는 이름에 대한 새 어트리뷰트를 만듭니다.

class ctypes.CField(*args, **kw)

Structure 및 :class:`Union`의 필드 디스크립터입니다. 예시:

>>> class Color(Structure):
...     _fields_ = (
...         ('red', c_uint8),
...         ('green', c_uint8),
...         ('blue', c_uint8),
...         ('intense', c_bool, 1),
...         ('blinking', c_bool, 1),
...    )
...
>>> Color.red
<ctypes.CField 'red' type=c_ubyte, ofs=0, size=1>
>>> Color.green.type
<class 'ctypes.c_ubyte'>
>>> Color.blue.byte_offset
2
>>> Color.intense
<ctypes.CField 'intense' type=c_bool, ofs=3, bit_size=1, bit_offset=0>
>>> Color.blinking.bit_offset
1

모든 어트리뷰트는 읽기 전용입니다.

CField 객체는 :attr:`~Structure._fields_`를 통해 생성됩니다. 이 클래스를 직접 인스턴스화하지 마십시오.

Added in version 3.14: 이전에는 디스크립터가 offsetsize 어트리뷰트와 읽기 가능한 문자열 표현만 갖고 있었으며, CField 클래스는 직접 사용할 수 없었습니다.

name

필드의 이름입니다 (문자열).

type

필드의 유형입니다 ( ctypes class ).

offset
byte_offset

필드 오프셋은 바이트 단위로 측정됩니다.

비트 필드의 경우, 이는 근본적인 byte-aligned 저장 단위 의 오프셋입니다. bit_offset 을 참조하십시오.

byte_size

필드 크기는 바이트 단위로 측정됩니다.

비트 필드의 경우, 이는 근본적인 저장 단위 의 크기입니다. 일반적으로 비트 필드의 타입과 같은 크기를 가집니다.

size

비트 필드가 아닌 경우 :attr:`~CField.byte_size`와 같습니다.

비트 필드의 경우, 이 값은 :attr:`~CField.bit_size`와 :attr:`~CField.bit_offset`을 결합한 비트 패킹된 역방향 호환 값을 포함합니다. 명시적인 속성 사용이 좋습니다.

is_bitfield

이것이 비트 필드인지 여부입니다.

bit_offset
bit_size

비트 필드가 그 저장 단위 내에서 위치하는 곳, 즉 byte_size 바이트 범위의 메모리 내에서의 위치입니다.

필드의 값을 얻으려면, 저장 단위를 정수로 읽은 다음, 해당 값에 <shifting>`로 :attr:!bit_offset`만큼 왼쪽으로 시프트하고 십진수 최하위 bit_size 비트를 추출하십시오.

비트 필드가 아닌 경우, bit_offset`은 0이고 :attr:!bit_size`는 `byte_size * 8`과 같습니다.

is_anonymous

이 필드가 익명(anonymous)인 경우 참입니다. 즉, 포함구조체나 유니온으로 병합되어야 하는 중첩된 하위-필드를 포함합니다.

배열과 포인터

class ctypes.Array(*args)

배열의 추상 베이스 클래스.

구체적인 배열 타입을 생성하는 권장 방법은 모든 ctypes 데이터를 비음수 정수와 곱하는 것입니다. 대안으로, 이 타입의 서브클래스를 만들고 _length__type_ 클래스 변수를 정의할 수 있습니다. 배열 요소는 표준 인덱싱 및 슬라이스 접근을 사용하여 읽고 쓸 수 있으며, 슬라이스 읽기의 결과 객체 자체는 Array 가 아닙니다.

배열은 자신들의 요소 타입에 대한 :ref:`<generics>`입니다.

_length_

배열의 요소 수를 지정하는 양의 정수. 범위를 벗어나는 서브 스크립트는 IndexError를 일으킵니다. len()에 의해 반환됩니다.

_type_

배열의 각 요소 형을 지정합니다.

Array 서브 클래스 생성자는 요소를 순서대로 초기화하는 데 사용되는 위치 인자를 받아들입니다.

ctypes.ARRAY(type, length)

Create an array. Equivalent to type * length, where type is a ctypes data type and length an integer.

버전 3.14부터 약하게 폐지 <Soft deprecated>: 곱하기가 선호됩니다.

class ctypes._Pointer

포인터를 위한 내부 추상 베이스 클래스.

구상 포인터형은 가리킬 형으로 POINTER()를 호출해서 만들어집니다; 이것은 pointer()에 의해 자동으로 수행됩니다.

포인터가 배열을 가리키면, 그것의 요소는 표준 서브 스크립트 및 슬라이스 액세스를 사용하여 읽고 쓸 수 있습니다. 포인터 객체는 크기가 없으므로, len()TypeError를 발생시킵니다. 음수 서브 스크립트는 (C처럼) 포인터 앞의 메모리를 읽을 것이고, 범위를 벗어나는 서브 스크립트는 (운이 좋다면) 액세스 위반으로 인해 충돌을 일으킬 것입니다.

_type_

가리키는 형을 지정합니다.

contents

포인터가 가리키는 객체를 반환합니다. 이 어트리뷰트에 대입하면 대입된 객체를 가리키도록 포인터가 변경됩니다.

예외

exception ctypes.ArgumentError

외부 함수 호출이 전달된 인자 중 하나를 변환할 수 없을 때 발생하는 예외.

exception ctypes.COMError(hresult, text, details)

이 예외는 COM 메서드 호출이 실패했을 때 발생합니다.

hresult

에러 코드를 나타내는 정수 값입니다.

text

에러 메시지입니다.

details

5-튜플 (descr, source, helpfile, helpcontext, progid) 입니다.

descr 는 텍스트 설명이고, source 는 오류를 발생시킨 클래스나 애플리케이션의 언어 의존적인 ProgID 입니다. helpfile 은 도움말 파일의 경로이며, helpcontext 는 도움말 컨텍스트 식별자입니다. progid 는 오류를 정의한 인터페이스의 ProgID 입니다.

가용성: Windows

Added in version 3.14.

분실물 보관소