日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

python ctypes中文幫助文檔

 dinghj 2019-04-17

   15.17。ctypes- 用于Python的外部函數(shù)庫

2.5版中的新功能。

ctypes是Python的外部函數(shù)庫。它提供C兼容的數(shù)據(jù)類型,并允許在DLL或共享庫中調(diào)用函數(shù)。它可以用于在純Python中包裝這些庫。

15.17.1。ctypes教程

注意:本教程中的代碼示例doctest用于確保它們實(shí)際工作。由于某些代碼示例在Linux,Windows或Mac OS X下的行為不同,因此它們在注釋中包含doctest指令。

注意:某些代碼示例引用了ctypes c_int類型。此類型是c_long32位系統(tǒng)上類型的別名。因此,c_long如果您打算如果打印,則不應(yīng)該感到困惑c_int- 它們實(shí)際上是相同的類型。

   15.17.1.1。加載動(dòng)態(tài)鏈接庫

ctypes導(dǎo)出cdll,以及Windows windlloledll 對象,用于加載動(dòng)態(tài)鏈接庫。

您可以通過訪問它們作為這些對象的屬性來加載庫。cdll 加載使用標(biāo)準(zhǔn)cdecl調(diào)用約定導(dǎo)出函數(shù)的庫,而windll庫使用stdcall 調(diào)用約定調(diào)用函數(shù)。oledll還使用stdcall調(diào)用約定,并假定函數(shù)返回Windows HRESULT錯(cuò)誤代碼。錯(cuò)誤代碼用于WindowsError在函數(shù)調(diào)用失敗時(shí)自動(dòng)引發(fā)異常。

以下是Windows的一些示例。注意,它msvcrt是包含大多數(shù)標(biāo)準(zhǔn)C函數(shù)的MS標(biāo)準(zhǔn)C庫,并使用cdecl調(diào)用約定:

  1. >>> from ctypes import *
  2. >>> print windll.kernel32
  3. <WinDLL 'kernel32', handle ... at ...>
  4. >>> print cdll.msvcrt
  5. <CDLL 'msvcrt', handle ... at ...>
  6. >>> libc = cdll.msvcrt
  7. >>>

Windows會(huì).dll自動(dòng)附加常用的文件后綴。

在Linux上,需要指定包含加載庫的擴(kuò)展名的文件名,因此不能使用屬性訪問來加載庫。LoadLibrary()應(yīng)該使用dll加載器的 方法,或者你應(yīng)該通過調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)CDLL實(shí)例來加載庫:

  1. >>> cdll.LoadLibrary("libc.so.6")
  2. <CDLL 'libc.so.6', handle ... at ...>
  3. >>> libc = CDLL("libc.so.6")
  4. >>> libc
  5. <CDLL 'libc.so.6', handle ... at ...>
  6. >>>

   15.17.1.2。從加載的dll訪問函數(shù)

函數(shù)作為dll對象的屬性進(jìn)行訪問:

  1. >>> from ctypes import *
  2. >>> libc.printf
  3. <_FuncPtr object at 0x...>
  4. >>> print windll.kernel32.GetModuleHandleA
  5. <_FuncPtr object at 0x...>
  6. >>> print windll.kernel32.MyOwnFunction
  7. Traceback (most recent call last):
  8. File "<stdin>", line 1, in <module>
  9. File "ctypes.py", line 239, in __getattr__
  10. func = _StdcallFuncPtr(name, self)
  11. AttributeError: function 'MyOwnFunction' not found
  12. >>>

請注意,win32系統(tǒng)類似于kernel32并且user32經(jīng)常導(dǎo)出ANSI以及函數(shù)的UNICODE版本。UNICODE版本將導(dǎo)出W并附加到名稱,而ANSI版本將導(dǎo)出A 并附加到名稱。win32 GetModuleHandle函數(shù)返回給定模塊名稱的 模塊句柄,具有以下C原型,并且GetModuleHandle根據(jù)是否定義了UNICODE ,使用宏來公開其中一個(gè):

  1. /* ANSI version */
  2. HMODULE GetModuleHandleA(LPCSTR lpModuleName);
  3. /* UNICODE version */
  4. HMODULE GetModuleHandleW(LPCWSTR lpModuleName);

windll不會(huì)嘗試通過魔法選擇其中一個(gè),您必須通過指定GetModuleHandleAGetModuleHandleW 顯式訪問所需的版本,然后分別使用字符串或unicode字符串調(diào)用它。

有時(shí),dll導(dǎo)出的函數(shù)名稱不是有效的Python標(biāo)識(shí)符,例如"??2@YAPAXI@Z"。在這種情況下,您必須使用 getattr()檢索功能:

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

在Windows上,某些dll不按名稱導(dǎo)出函數(shù),而是按順序?qū)С龊瘮?shù)??梢酝ㄟ^使用序號(hào)索引dll對象來訪問這些函數(shù):

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

    15.17.1.3。調(diào)用函數(shù)

您可以像調(diào)用任何其他Python一樣調(diào)用這些函數(shù)。此示例使用time()函數(shù),該函數(shù)返回自Unix紀(jì)元以來以秒為單位的系統(tǒng)時(shí)間,以及GetModuleHandleA()返回win32模塊句柄的函數(shù)。

此示例使用NULL指針調(diào)用這兩個(gè)函數(shù)(None應(yīng)該用作NULL指針):

  1. >>> print libc.time(None)
  2. 1150640792
  3. >>> print hex(windll.kernel32.GetModuleHandleA(None))
  4. 0x1d000000
  5. >>>

ctypes試圖保護(hù)您不要使用錯(cuò)誤的參數(shù)數(shù)量或錯(cuò)誤的調(diào)用約定來調(diào)用函數(shù)。不幸的是,這僅適用于Windows。它通過在函數(shù)返回后檢查堆棧來完成此操作,因此雖然引發(fā)了錯(cuò)誤,但函數(shù)被調(diào)用:

  1. >>> windll.kernel32.GetModuleHandleA()
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. ValueError: Procedure probably called with not enough arguments (4 bytes missing)
  5. >>> windll.kernel32.GetModuleHandleA(0, 0)
  6. Traceback (most recent call last):
  7. File "<stdin>", line 1, in <module>
  8. ValueError: Procedure probably called with too many arguments (4 bytes in excess)
  9. >>>

stdcall使用cdecl調(diào)用約定調(diào)用函數(shù) 時(shí)會(huì)引發(fā)相同的異常,反之亦然:

  1. >>> cdll.kernel32.GetModuleHandleA(None)
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. ValueError: Procedure probably called with not enough arguments (4 bytes missing)
  5. >>>
  6. >>> windll.msvcrt.printf("spam")
  7. Traceback (most recent call last):
  8. File "<stdin>", line 1, in <module>
  9. ValueError: Procedure probably called with too many arguments (4 bytes in excess)
  10. >>>

要找出正確的調(diào)用約定,您必須查看C頭文件或要調(diào)用的函數(shù)的文檔。

在Windows上,ctypes使用win32結(jié)構(gòu)化異常處理來防止在使用無效參數(shù)值調(diào)用函數(shù)時(shí)因常規(guī)保護(hù)錯(cuò)誤而崩潰:

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

但是,有足夠的方法可以使Python崩潰ctypes,所以無論如何你應(yīng)該小心。

None,整數(shù),長整數(shù),字節(jié)字符串和unicode字符串是唯一可以直接用作這些函數(shù)調(diào)用中的參數(shù)的本機(jī)Python對象。 None作為C NULL指針傳遞,字節(jié)字符串和unicode字符串作為指針傳遞給包含其數(shù)據(jù)( 或)的內(nèi)存塊。Python整數(shù)和Python long作為平臺(tái)默認(rèn)C 類型傳遞,它們的值被屏蔽以適合C類型。char *wchar_t *int

在我們繼續(xù)使用其他參數(shù)類型調(diào)用函數(shù)之前,我們必須了解有關(guān)ctypes數(shù)據(jù)類型的更多信息。

   15.17.1.4。基本數(shù)據(jù)類型

ctypes 定義了許多原始C兼容的數(shù)據(jù)類型:

ctypes類型 C型 Python類型
c_bool _Bool 布爾(1)
c_char char 1個(gè)字符的字符串
c_wchar wchar_t 1個(gè)字符的unicode字符串
c_byte char INT /長
c_ubyte unsigned char INT /長
c_short short INT /長
c_ushort unsigned short INT /長
c_int int INT /長
c_uint unsigned int INT /長
c_long long INT /長
c_ulong unsigned long INT /長
c_longlong __int64 要么 long long INT /長
c_ulonglong unsigned __int64 要么 unsigned long long INT /長
c_float float 浮動(dòng)
c_double double 浮動(dòng)
c_longdouble long double 浮動(dòng)
c_char_p char * (NUL終止) 字符串或 None
c_wchar_p wchar_t * (NUL終止) unicode或 None
c_void_p void * int / long或 None
  1. 構(gòu)造函數(shù)接受具有真值的任何對象。

所有這些類型都可以通過使用正確類型和值的可選初始化程序調(diào)用它們來創(chuàng)建:

  1. >>> c_int()
  2. c_long(0)
  3. >>> c_char_p("Hello, World")
  4. c_char_p('Hello, World')
  5. >>> c_ushort(-3)
  6. c_ushort(65533)
  7. >>>

由于這些類型是可變的,因此它們的值也可以在以后更改:

  1. >>> i = c_int(42)
  2. >>> print i
  3. c_long(42)
  4. >>> print i.value
  5. 42
  6. >>> i.value = -99
  7. >>> print i.value
  8. -99
  9. >>>

分配一個(gè)新的值,將指針類型的實(shí)例c_char_p, c_wchar_p以及c_void_p改變所述存儲(chǔ)器位置它們指向,而不是內(nèi)容的內(nèi)存塊(當(dāng)然不是,因?yàn)镻ython字符串是不可變的):

  1. >>> s = "Hello, World"
  2. >>> c_s = c_char_p(s)
  3. >>> print c_s
  4. c_char_p('Hello, World')
  5. >>> c_s.value = "Hi, there"
  6. >>> print c_s
  7. c_char_p('Hi, there')
  8. >>> print s # first string is unchanged
  9. Hello, World
  10. >>>

但是,您應(yīng)該小心,不要將它們傳遞給期望指向可變內(nèi)存的函數(shù)。如果你需要可變的內(nèi)存塊,ctypes有一個(gè)create_string_buffer()以各種方式創(chuàng)建它們的 函數(shù)。可以使用raw 屬性訪問(或更改)當(dāng)前內(nèi)存塊內(nèi)容; 如果要以NUL終止字符串的形式訪問它,請使用以下value 屬性:

  1. >>> from ctypes import *
  2. >>> p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytes
  3. >>> print sizeof(p), repr(p.raw)
  4. 3 '\x00\x00\x00'
  5. >>> p = create_string_buffer("Hello") # create a buffer containing a NUL terminated string
  6. >>> print sizeof(p), repr(p.raw)
  7. 6 'Hello\x00'
  8. >>> print repr(p.value)
  9. 'Hello'
  10. >>> p = create_string_buffer("Hello", 10) # create a 10 byte buffer
  11. >>> print sizeof(p), repr(p.raw)
  12. 10 'Hello\x00\x00\x00\x00\x00'
  13. >>> p.value = "Hi"
  14. >>> print sizeof(p), repr(p.raw)
  15. 10 'Hi\x00lo\x00\x00\x00\x00\x00'
  16. >>>

create_string_buffer()函數(shù)替換了c_buffer()函數(shù)(仍可作為別名使用),以及c_string()早期ctypes版本中的函數(shù)。要?jiǎng)?chuàng)建包含C類型的unicode字符的可變內(nèi)存塊,請wchar_t使用該 create_unicode_buffer()函數(shù)。

   15.17.1.5。調(diào)用函數(shù),續(xù)

需要注意的是的printf打印到實(shí)際的標(biāo)準(zhǔn)輸出通道,給 sys.stdout,所以這些例子只是在控制臺(tái)提示符下運(yùn)行,而不是從內(nèi)IDLEPythonWin的

  1. >>> printf = libc.printf
  2. >>> printf("Hello, %s\n", "World!")
  3. Hello, World!
  4. 14
  5. >>> printf("Hello, %S\n", u"World!")
  6. Hello, World!
  7. 14
  8. >>> printf("%d bottles of beer\n", 42)
  9. 42 bottles of beer
  10. 19
  11. >>> printf("%f bottles of beer\n", 42.5)
  12. Traceback (most recent call last):
  13. File "<stdin>", line 1, in <module>
  14. ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2
  15. >>>

如前所述,除了整數(shù),字符串和unicode字符串之外的所有Python類型都必須包裝在相應(yīng)的ctypes類型中,以便它們可以轉(zhuǎn)換為所需的C數(shù)據(jù)類型:

  1. >>> printf("An int %d, a double %f\n", 1234, c_double(3.14))
  2. An int 1234, a double 3.140000
  3. 31
  4. >>>

    15.17.1.6。使用自己的自定義數(shù)據(jù)類型調(diào)用函數(shù)

您還可以自定義ctypes參數(shù)轉(zhuǎn)換,以允許將您自己的類的實(shí)例用作函數(shù)參數(shù)。 ctypes查找 _as_parameter_屬性并將其用作函數(shù)參數(shù)。當(dāng)然,它必須是整數(shù),字符串或unicode之一:

  1. >>> class Bottles(object):
  2. ... def __init__(self, number):
  3. ... self._as_parameter_ = number
  4. ...
  5. >>> bottles = Bottles(42)
  6. >>> printf("%d bottles of beer\n", bottles)
  7. 42 bottles of beer
  8. 19
  9. >>>

如果您不想將實(shí)例的數(shù)據(jù)存儲(chǔ)在_as_parameter_ 實(shí)例變量中,則可以定義property()使數(shù)據(jù)可用的數(shù)據(jù)。

   15.17.1.7。指定必需的參數(shù)類型(函數(shù)原型)

可以通過設(shè)置argtypes屬性來指定從DLL導(dǎo)出的函數(shù)所需的參數(shù)類型。

argtypes必須是一系列C數(shù)據(jù)類型(這里的printf函數(shù)可能不是一個(gè)很好的例子,因?yàn)樗Q于格式字符串需要一個(gè)可變數(shù)字和不同類型的參數(shù),另一方面,這對于試驗(yàn)這個(gè)特性非常方便) :

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

指定格式可以防止不兼容的參數(shù)類型(就像C函數(shù)的原型一樣),并嘗試將參數(shù)轉(zhuǎn)換為有效類型:

  1. >>> printf("%d %d %d", 1, 2, 3)
  2. Traceback (most recent call last):
  3. File "<stdin>", line 1, in <module>
  4. ArgumentError: argument 2: exceptions.TypeError: wrong type
  5. >>> printf("%s %d %f\n", "X", 2, 3)
  6. X 2 3.000000
  7. 13
  8. >>>

如果已經(jīng)定義了自己傳遞給函數(shù)調(diào)用的from_param()類,則必須為它們實(shí)現(xiàn)一個(gè)類方法,以便能夠在argtypes序列中使用它們。本from_param()類方法接收傳給函數(shù)的Python對象,它做一個(gè)類型檢測,或者是需要確保這個(gè)對象是可接受的,然后返回對象本身,它_as_parameter_不管你想傳遞的C函數(shù)屬性,或在這種情況下的論點(diǎn)。同樣,結(jié)果應(yīng)該是整數(shù),字符串,unicode,ctypes實(shí)例或具有_as_parameter_屬性的對象 。

   15.17.1.8。返回類型

默認(rèn)情況下,假定函數(shù)返回C int類型??梢酝ㄟ^設(shè)置restype函數(shù)對象的屬性來指定其他返回類型。

這是一個(gè)更高級的示例,它使用strchr函數(shù),它需要一個(gè)字符串指針和一個(gè)char,并返回一個(gè)指向字符串的指針:

  1. >>> strchr = libc.strchr
  2. >>> strchr("abcdef", ord("d"))
  3. 8059983
  4. >>> strchr.restype = c_char_p # c_char_p is a pointer to a string
  5. >>> strchr("abcdef", ord("d"))
  6. 'def'
  7. >>> print strchr("abcdef", ord("x"))
  8. None
  9. >>>

如果要避免ord("x")上面的調(diào)用,可以設(shè)置 argtypes屬性,第二個(gè)參數(shù)將從單個(gè)字符Python字符串轉(zhuǎn)換為C字符:

  1. >>> strchr.restype = c_char_p
  2. >>> strchr.argtypes = [c_char_p, c_char]
  3. >>> strchr("abcdef", "d")
  4. 'def'
  5. >>> strchr("abcdef", "def")
  6. Traceback (most recent call last):
  7. File "<stdin>", line 1, in <module>
  8. ArgumentError: argument 2: exceptions.TypeError: one character string expected
  9. >>> print strchr("abcdef", "x")
  10. None
  11. >>> strchr("abcdef", "d")
  12. 'def'
  13. >>>

restype如果外部函數(shù)返回一個(gè)整數(shù),您還可以使用可調(diào)用的Python對象(例如函數(shù)或類)作為屬性。將使用C函數(shù)返回的整數(shù)調(diào)用callable ,并且此調(diào)用的結(jié)果將用作函數(shù)調(diào)用的結(jié)果。這對于檢查錯(cuò)誤返回值并自動(dòng)引發(fā)異常非常有用:

  1. >>> GetModuleHandle = windll.kernel32.GetModuleHandleA
  2. >>> def ValidHandle(value):
  3. ... if value == 0:
  4. ... raise WinError()
  5. ... return value
  6. ...
  7. >>>
  8. >>> GetModuleHandle.restype = ValidHandle
  9. >>> GetModuleHandle(None)
  10. 486539264
  11. >>> GetModuleHandle("something silly")
  12. Traceback (most recent call last):
  13. File "<stdin>", line 1, in <module>
  14. File "<stdin>", line 3, in ValidHandle
  15. WindowsError: [Errno 126] The specified module could not be found.
  16. >>>

WinError是一個(gè)函數(shù),它將調(diào)用Windows FormatMessage()api來獲取錯(cuò)誤代碼的字符串表示,并返回一個(gè)異常。 WinError采用可選的錯(cuò)誤代碼參數(shù),如果沒有使用,則調(diào)用它 GetLastError()來檢索它。

請注意,通過該errcheck屬性可以使用更強(qiáng)大的錯(cuò)誤檢查機(jī)制; 有關(guān)詳細(xì)信息,請參閱參考手冊

   15.17.1.9。傳遞指針(或:通過引用傳遞參數(shù))

有時(shí),C api函數(shù)需要將指向數(shù)據(jù)類型的指針作為參數(shù),可能要寫入相應(yīng)的位置,或者數(shù)據(jù)太大而無法通過值傳遞。這也稱為通過引用傳遞參數(shù)。

ctypes導(dǎo)出byref()用于通過引用傳遞參數(shù)的函數(shù)。使用該pointer()函數(shù)可以實(shí)現(xiàn)相同的效果 ,但是pointer()由于它構(gòu)造了一個(gè)真正的指針對象,所以工作量更大,因此byref()如果您不需要Python本身的指針對象,則使用它會(huì)更快:

  1. >>> i = c_int()
  2. >>> f = c_float()
  3. >>> s = create_string_buffer('\000' * 32)
  4. >>> print i.value, f.value, repr(s.value)
  5. 0 0.0 ''
  6. >>> libc.sscanf("1 3.14 Hello", "%d %f %s",
  7. ... byref(i), byref(f), s)
  8. 3
  9. >>> print i.value, f.value, repr(s.value)
  10. 1 3.1400001049 'Hello'
  11. >>>

   15.17.1.10。結(jié)構(gòu)和聯(lián)合

結(jié)構(gòu)和聯(lián)合必須從導(dǎo)出StructureUnion 其中所定義的基類ctypes模塊。每個(gè)子類都必須定義一個(gè)_fields_屬性。 _fields_必須是2元組的列表 ,包含字段名稱字段類型。

字段類型必須是ctypes類型c_int或任何其他派生ctypes類型:結(jié)構(gòu),聯(lián)合,數(shù)組,指針。

下面是一個(gè)POINT結(jié)構(gòu)的簡單示例,它包含兩個(gè)名為xy的整數(shù) ,還顯示了如何在構(gòu)造函數(shù)中初始化結(jié)構(gòu):

  1. >>> from ctypes import *
  2. >>> class POINT(Structure):
  3. ... _fields_ = [("x", c_int),
  4. ... ("y", c_int)]
  5. ...
  6. >>> point = POINT(10, 20)
  7. >>> print point.x, point.y
  8. 10 20
  9. >>> point = POINT(y=5)
  10. >>> print point.x, point.y
  11. 0 5
  12. >>> POINT(1, 2, 3)
  13. Traceback (most recent call last):
  14. File "<stdin>", line 1, in <module>
  15. ValueError: too many initializers
  16. >>>

但是,您可以構(gòu)建更復(fù)雜的結(jié)構(gòu)。通過將結(jié)構(gòu)用作字段類型,結(jié)構(gòu)本身可以包含其他結(jié)構(gòu)。

這是一個(gè)RECT結(jié)構(gòu),它包含兩個(gè)名為upperleft和 lowerright的POINT

  1. >>> class RECT(Structure):
  2. ... _fields_ = [("upperleft", POINT),
  3. ... ("lowerright", POINT)]
  4. ...
  5. >>> rc = RECT(point)
  6. >>> print rc.upperleft.x, rc.upperleft.y
  7. 0 5
  8. >>> print rc.lowerright.x, rc.lowerright.y
  9. 0 0
  10. >>>

嵌套結(jié)構(gòu)也可以通過以下幾種方式在構(gòu)造函數(shù)中初始化:

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

字段描述符 S可從被檢索,它們可用于調(diào)試有用,因?yàn)樗鼈兛梢蕴峁┯杏玫男畔ⅲ?/p>

  1. >>> print POINT.x
  2. <Field type=c_long, ofs=0, size=4>
  3. >>> print POINT.y
  4. <Field type=c_long, ofs=4, size=4>
  5. >>>

警告

ctypes不支持通過值將具有位字段的聯(lián)合或結(jié)構(gòu)傳遞給函數(shù)。雖然這可能適用于32位x86,但是不能保證庫在一般情況下工作。具有位字段的聯(lián)合和結(jié)構(gòu)應(yīng)始終通過指針傳遞給函數(shù)。

   15.17.1.11。結(jié)構(gòu)/聯(lián)合對齊和字節(jié)順序

默認(rèn)情況下,Structure和Union字段的對齊方式與C編譯器的方式相同??梢酝ㄟ^_pack_在子類定義中指定類屬性來覆蓋此行為 。必須將其設(shè)置為正整數(shù),并指定字段的最大對齊方式。這也是MSVC中的做法。#pragma pack(n)

ctypes使用結(jié)構(gòu)和聯(lián)合的本機(jī)字節(jié)順序。要建立與非本地字節(jié)順序結(jié)構(gòu),你可以使用一個(gè) BigEndianStructure,LittleEndianStructure, BigEndianUnion,和LittleEndianUnion基類。這些類不能包含指針字段。

   15.17.1.12。結(jié)構(gòu)和聯(lián)合中的位字段

可以創(chuàng)建包含位字段的結(jié)構(gòu)和聯(lián)合。位字段僅適用于整數(shù)字段,位寬指定為_fields_元組中的第三項(xiàng):

  1. >>> class Int(Structure):
  2. ... _fields_ = [("first_16", c_int, 16),
  3. ... ("second_16", c_int, 16)]
  4. ...
  5. >>> print Int.first_16
  6. <Field type=c_long, ofs=0:0, bits=16>
  7. >>> print Int.second_16
  8. <Field type=c_long, ofs=0:16, bits=16>
  9. >>>

   15.17.1.13。數(shù)組

數(shù)組是序列,包含固定數(shù)量的相同類型的實(shí)例。

創(chuàng)建數(shù)組類型的推薦方法是將數(shù)據(jù)類型與正整數(shù)相乘:

TenPointsArrayType = POINT * 10

這是一個(gè)有點(diǎn)人為的數(shù)據(jù)類型的例子,一個(gè)包含4個(gè)POINT和其他東西的結(jié)構(gòu):

  1. >>> from ctypes import *
  2. >>> class POINT(Structure):
  3. ... _fields_ = ("x", c_int), ("y", c_int)
  4. ...
  5. >>> class MyStruct(Structure):
  6. ... _fields_ = [("a", c_int),
  7. ... ("b", c_float),
  8. ... ("point_array", POINT * 4)]
  9. >>>
  10. >>> print len(MyStruct().point_array)
  11. 4
  12. >>>

通過調(diào)用類以通常的方式創(chuàng)建實(shí)例:

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

上面的代碼打印了一系列行,因?yàn)閿?shù)組內(nèi)容被初始化為零。0 0

也可以指定正確類型的初始化器:

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

   15.17.1.14。指針

通過pointer()ctypes類型上調(diào)用函數(shù) 來創(chuàng)建指針實(shí)例:

  1. >>> from ctypes import *
  2. >>> i = c_int(42)
  3. >>> pi = pointer(i)
  4. >>>

指針實(shí)例有一個(gè)contents屬性,它返回指針指向的i對象,上面的對象:

  1. >>> pi.contents
  2. c_long(42)
  3. >>>

注意,ctypes沒有OOR(原始對象返回),每次檢索屬性時(shí)它都會(huì)構(gòu)造一個(gè)新的等效對象:

  1. >>> pi.contents is i
  2. False
  3. >>> pi.contents is pi.contents
  4. False
  5. >>>

將另一個(gè)c_int實(shí)例分配給指針的contents屬性會(huì)導(dǎo)致指針指向存儲(chǔ)它的內(nèi)存位置:

  1. >>> i = c_int(99)
  2. >>> pi.contents = i
  3. >>> pi.contents
  4. c_long(99)
  5. >>>

指針實(shí)例也可以用整數(shù)索引:

  1. >>> pi[0]
  2. 99
  3. >>>

分配整數(shù)索引會(huì)更改指向的值:

  1. >>> print i
  2. c_long(99)
  3. >>> pi[0] = 22
  4. >>> print i
  5. c_long(22)
  6. >>>

也可以使用不同于0的索引,但您必須知道自己在做什么,就像在C中一樣:您可以訪問或更改任意內(nèi)存位置。通常,如果從C函數(shù)接收指針,則只使用此功能,并且您知道指針實(shí)際指向的是數(shù)組而不是單個(gè)項(xiàng)。

在幕后,該pointer()函數(shù)不僅僅是創(chuàng)建指針實(shí)例,還必須首先創(chuàng)建指針類型。這是通過POINTER()接受任何ctypes類型的函數(shù)完成的,并返回一個(gè)新類型:

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

調(diào)用不帶參數(shù)的指針類型會(huì)創(chuàng)建NULL指針。 NULL指針有一個(gè)False布爾值:

  1. >>> null_ptr = POINTER(c_int)()
  2. >>> print bool(null_ptr)
  3. False
  4. >>>

ctypes檢查NULL何時(shí)解除引用指針(但解除引用無效的非NULL指針會(huì)使Python崩潰):

  1. >>> null_ptr[0]
  2. Traceback (most recent call last):
  3. ....
  4. ValueError: NULL pointer access
  5. >>>
  6. >>> null_ptr[0] = 1234
  7. Traceback (most recent call last):
  8. ....
  9. ValueError: NULL pointer access
  10. >>>

   15.17.1.15。輸入轉(zhuǎn)換

通常,ctypes會(huì)進(jìn)行嚴(yán)格的類型檢查。這意味著,如果您 POINTER(c_int)argtypes函數(shù)列表中或在結(jié)構(gòu)定義中具有成員字段的類型,則只接受完全相同類型的實(shí)例。此規(guī)則有一些例外,其中ctypes接受其他對象。例如,您可以傳遞兼容的數(shù)組實(shí)例而不是指針類型。因此,對于POINTER(c_int),ctypes接受一個(gè)c_int數(shù)組:

  1. >>> class Bar(Structure):
  2. ... _fields_ = [("count", c_int), ("values", POINTER(c_int))]
  3. ...
  4. >>> bar = Bar()
  5. >>> bar.values = (c_int * 3)(1, 2, 3)
  6. >>> bar.count = 3
  7. >>> for i in range(bar.count):
  8. ... print bar.values[i]
  9. ...
  10. 1
  11. 2
  12. 3
  13. >>>

此外,如果函數(shù)參數(shù)顯式聲明為指針類型(例如POINTER(c_int))in argtypes,則可以將指向類型的對象(c_int在本例中)傳遞給函數(shù)。ctypes將自動(dòng)應(yīng)用所需的byref()轉(zhuǎn)換。

要將POINTER類型字段設(shè)置為NULL,您可以指定None

  1. >>> bar.values = None
  2. >>>

有時(shí)您會(huì)遇到不兼容類型的實(shí)例。在C中,您可以將一種類型轉(zhuǎn)換為另一種類型。 ctypes提供cast()可以以相同方式使用的功能。Bar上面定義的結(jié)構(gòu)接受 其字段的POINTER(c_int)指針或c_int數(shù)組values,但不接受其他類型的實(shí)例:

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

對于這些情況,該cast()功能很方便,cast還支持將python中的id(obj)即對象地址還原為對象

cast()函數(shù)可用于將ctypes實(shí)例轉(zhuǎn)換為指向不同ctypes數(shù)據(jù)類型的指針。 cast()采用兩個(gè)參數(shù),一個(gè)或者可以轉(zhuǎn)換為某種指針的ctypes對象,以及一個(gè)ctypes指針類型。它返回第二個(gè)參數(shù)的實(shí)例,它引用與第一個(gè)參數(shù)相同的內(nèi)存塊:

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

所以,cast()可以用來分配給結(jié)構(gòu)的values字段Bar

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

   15.17.1.16。不完全類型

不完整類型是其成員尚未指定的結(jié)構(gòu),聯(lián)合或數(shù)組。在C中,它們由前向聲明指定,后面將定義:

  1. struct cell; /* forward declaration */
  2. struct cell {
  3. char *name;
  4. struct cell *next;
  5. };

直接轉(zhuǎn)換為ctypes代碼就是這樣,但它不起作用:

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

因?yàn)閚ew 語句本身不可用。在,我們可以 在類語句之后定義類并設(shè)置屬性:class cellctypescell_fields_

  1. >>> from ctypes import *
  2. >>> class cell(Structure):
  3. ... pass
  4. ...
  5. >>> cell._fields_ = [("name", c_char_p),
  6. ... ("next", POINTER(cell))]
  7. >>>

讓我們試試吧。我們創(chuàng)建了兩個(gè)實(shí)例cell,并讓它們相互指向,最后跟隨指針鏈幾次:

  1. >>> c1 = cell()
  2. >>> c1.name = "foo"
  3. >>> c2 = cell()
  4. >>> c2.name = "bar"
  5. >>> c1.next = pointer(c2)
  6. >>> c2.next = pointer(c1)
  7. >>> p = c1
  8. >>> for i in range(8):
  9. ... print p.name,
  10. ... p = p.next[0]
  11. ...
  12. foo bar foo bar foo bar foo bar
  13. >>>

   15.17.1.17?;卣{(diào)函數(shù)

ctypes允許從Python callables創(chuàng)建C可調(diào)用函數(shù)指針。這些有時(shí)稱為回調(diào)函數(shù)。

首先,您必須為回調(diào)函數(shù)創(chuàng)建一個(gè)類,該類知道調(diào)用約定,返回類型以及此函數(shù)將接收的參數(shù)的數(shù)量和類型。

CFUNCTYPE工廠函數(shù)使用普通的cdecl調(diào)用約定為回調(diào)函數(shù)創(chuàng)建類型,在Windows上,WINFUNCTYPE工廠函數(shù)使用stdcall調(diào)用約定為回調(diào)函數(shù)創(chuàng)建類型。

這兩個(gè)工廠函數(shù)都以結(jié)果類型作為第一個(gè)參數(shù)調(diào)用,而回調(diào)函數(shù)將期望的參數(shù)類型作為其余參數(shù)。

我將在這里展示一個(gè)使用標(biāo)準(zhǔn)C庫qsort() 函數(shù)的示例,它用于在回調(diào)函數(shù)的幫助下對項(xiàng)目進(jìn)行排序。 qsort()將用于對整數(shù)數(shù)組進(jìn)行排序:

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

qsort()必須使用指向要排序的數(shù)據(jù)的指針,數(shù)據(jù)數(shù)組中的項(xiàng)數(shù),一個(gè)項(xiàng)的大小以及指向比較函數(shù)(回調(diào))的指針來調(diào)用。然后使用兩個(gè)指向項(xiàng)目的指針調(diào)用回調(diào),如果第一個(gè)項(xiàng)目小于第二個(gè)項(xiàng)目,它必須返回一個(gè)負(fù)整數(shù),如果它們相等則返回零,然后返回一個(gè)正整數(shù)。

所以我們的回調(diào)函數(shù)接收指向整數(shù)的指針,并且必須返回一個(gè)整數(shù)。首先我們type為回調(diào)函數(shù)創(chuàng)建:

  1. >>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
  2. >>>

對于回調(diào)函數(shù)的第一個(gè)實(shí)現(xiàn),我們只是打印我們得到的參數(shù),并返回0(增量開發(fā);-):

  1. >>> def py_cmp_func(a, b):
  2. ... print "py_cmp_func", a, b
  3. ... return 0
  4. ...
  5. >>>

創(chuàng)建C可調(diào)用回調(diào):

  1. >>> cmp_func = CMPFUNC(py_cmp_func)
  2. >>>

我們準(zhǔn)備好了:

  1. >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
  2. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  3. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  4. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  5. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  6. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  7. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  8. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  9. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  10. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  11. py_cmp_func <ctypes.LP_c_long object at 0x00...> <ctypes.LP_c_long object at 0x00...>
  12. >>>

我們知道如何訪問指針的內(nèi)容,所以讓我們重新定義我們的回調(diào):

  1. >>> def py_cmp_func(a, b):
  2. ... print "py_cmp_func", a[0], b[0]
  3. ... return 0
  4. ...
  5. >>> cmp_func = CMPFUNC(py_cmp_func)
  6. >>>

以下是我們在Windows上獲得的內(nèi)容:

  1. >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
  2. py_cmp_func 7 1
  3. py_cmp_func 33 1
  4. py_cmp_func 99 1
  5. py_cmp_func 5 1
  6. py_cmp_func 7 5
  7. py_cmp_func 33 5
  8. py_cmp_func 99 5
  9. py_cmp_func 7 99
  10. py_cmp_func 33 99
  11. py_cmp_func 7 33
  12. >>>

很有趣的是,在linux上,sort函數(shù)看起來效率更高,它做的比較少:

  1. >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
  2. py_cmp_func 5 1
  3. py_cmp_func 33 99
  4. py_cmp_func 7 33
  5. py_cmp_func 5 7
  6. py_cmp_func 1 7
  7. >>>

啊,我們差不多完成了!最后一步是實(shí)際比較這兩個(gè)項(xiàng)并返回一個(gè)有用的結(jié)果:

  1. >>> def py_cmp_func(a, b):
  2. ... print "py_cmp_func", a[0], b[0]
  3. ... return a[0] - b[0]
  4. ...
  5. >>>

最終在Windows上運(yùn)行:

  1. >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
  2. py_cmp_func 33 7
  3. py_cmp_func 99 33
  4. py_cmp_func 5 99
  5. py_cmp_func 1 99
  6. py_cmp_func 33 7
  7. py_cmp_func 1 33
  8. py_cmp_func 5 33
  9. py_cmp_func 5 7
  10. py_cmp_func 1 7
  11. py_cmp_func 5 1
  12. >>>

在Linux上:

  1. >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
  2. py_cmp_func 5 1
  3. py_cmp_func 33 99
  4. py_cmp_func 7 33
  5. py_cmp_func 1 7
  6. py_cmp_func 5 7
  7. >>>

很有趣的是,Windows qsort()功能需要比Linux版本更多的比較!

我們可以輕松檢查,我們的數(shù)組現(xiàn)在排序:

  1. >>> for i in ia: print i,
  2. ...
  3. 1 5 7 33 99
  4. >>>

注意

CFUNCTYPE()只要從C代碼中使用對象,請確保保留對對象的引用。ctypes沒有,如果你不這樣做,它們可能被垃圾收集,在回調(diào)時(shí)崩潰你的程序。

另外,請注意,如果在Python控件之外創(chuàng)建的線程中調(diào)用回調(diào)函數(shù)(例如,通過調(diào)用回調(diào)的外部代碼),ctypes會(huì)在每次調(diào)用時(shí)創(chuàng)建一個(gè)新的虛擬Python線程。這種行為是對大多數(shù)的目的是正確的,但它意味著存儲(chǔ)的值threading.local不會(huì)在不同的回調(diào)生存,即使這些電話是從同一個(gè)C的線。

   15.17.1.18。訪問從dll導(dǎo)出的值

一些共享庫不僅導(dǎo)出函數(shù),還導(dǎo)出變量。Python庫本身的一個(gè)示例是Py_OptimizeFlag,一個(gè)設(shè)置為0,1或2的整數(shù),具體取決于啟動(dòng)時(shí)給出的-O-OO標(biāo)志。

ctypes可以使用in_dll()類型的類方法訪問這樣的值。 pythonapi是一個(gè)預(yù)定義的符號(hào),可以訪問Python C api:

  1. >>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
  2. >>> print opt_flag
  3. c_long(0)
  4. >>>

如果解釋器已經(jīng)啟動(dòng)-O,則樣本將打印c_long(1),或者c_long(2)如果-OO已經(jīng)指定。

一個(gè)擴(kuò)展示例也演示了指針的使用,可以訪問PyImport_FrozenModulesPython導(dǎo)出的 指針。

引用Python文檔:此指針初始化為指向“struct _frozen”記錄的數(shù)組,由其成員全部為NULL或零的記錄終止。導(dǎo)入凍結(jié)模塊時(shí),將在此表中搜索它。第三方代碼可以使用此方法來提供動(dòng)態(tài)創(chuàng)建的凍結(jié)模塊集合。

所以操縱這個(gè)指針甚至可以證明是有用的。為了限制示例大小,我們僅顯示如何使用以下方法讀取此表ctypes

  1. >>> from ctypes import *
  2. >>>
  3. >>> class struct_frozen(Structure):
  4. ... _fields_ = [("name", c_char_p),
  5. ... ("code", POINTER(c_ubyte)),
  6. ... ("size", c_int)]
  7. ...
  8. >>>

我們已經(jīng)定義了數(shù)據(jù)類型,因此我們可以獲得指向表的指針:struct _frozen

  1. >>> FrozenTable = POINTER(struct_frozen)
  2. >>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
  3. >>>

因?yàn)?code>table是一個(gè)記錄pointer數(shù)組struct_frozen,我們可以迭代它,但我們必須確保我們的循環(huán)終止,因?yàn)橹羔槢]有大小。遲早它可能會(huì)因訪問沖突或其他原因而崩潰,所以當(dāng)我們點(diǎn)擊NULL條目時(shí)最好突破循環(huán):

  1. >>> for item in table:
  2. ... print item.name, item.size
  3. ... if item.name is None:
  4. ... break
  5. ...
  6. __hello__ 104
  7. __phello__ -104
  8. __phello__.spam 104
  9. None 0
  10. >>>

標(biāo)準(zhǔn)Python具有凍結(jié)模塊和凍結(jié)包(由負(fù)大小成員指示)的事實(shí)并不為人所知,它僅用于測試。例如嘗試一下。import __hello__

   15.17.1.19。驚喜

在某些邊緣情況下ctypes,您可能會(huì)發(fā)現(xiàn)實(shí)際情況以外的其他情況。

請考慮以下示例:

  1. >>> from ctypes import *
  2. >>> class POINT(Structure):
  3. ... _fields_ = ("x", c_int), ("y", c_int)
  4. ...
  5. >>> class RECT(Structure):
  6. ... _fields_ = ("a", POINT), ("b", POINT)
  7. ...
  8. >>> p1 = POINT(1, 2)
  9. >>> p2 = POINT(3, 4)
  10. >>> rc = RECT(p1, p2)
  11. >>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
  12. 1 2 3 4
  13. >>> # now swap the two points
  14. >>> rc.a, rc.b = rc.b, rc.a
  15. >>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y
  16. 3 4 3 4
  17. >>>

嗯。我們當(dāng)然希望打印最后一份聲明。發(fā)生了什么?以下是上述行的步驟:3 4 1 2rc.a, rc.b = rc.b, rc.a

  1. >>> temp0, temp1 = rc.b, rc.a
  2. >>> rc.a = temp0
  3. >>> rc.b = temp1
  4. >>>

請注意,temp0并且temp1還在使用的內(nèi)部緩沖器的對象rc上述對象。因此執(zhí)行將緩沖區(qū)內(nèi)容復(fù)制到緩沖區(qū)中。反過來,這改變了內(nèi)容。因此,最后一項(xiàng)任務(wù),沒有預(yù)期的效果。rc.a = temp0temp0rctemp1rc.b = temp1

請記住,從Structure,Unions和Arrays中檢索子對象不會(huì)復(fù)制子對象,而是檢索訪問根對象底層緩沖區(qū)的包裝器對象。

另一個(gè)可能與預(yù)期不同的例子是:

  1. >>> s = c_char_p()
  2. >>> s.value = "abc def ghi"
  3. >>> s.value
  4. 'abc def ghi'
  5. >>> s.value is s.value
  6. False
  7. >>>

為什么打印False?ctypes實(shí)例是包含內(nèi)存塊的對象以及訪問內(nèi)存內(nèi)容的一些描述符。在內(nèi)存塊中存儲(chǔ)Python對象不會(huì)存儲(chǔ)對象本身,而是存儲(chǔ)對象contents的對象。再次訪問內(nèi)容每次構(gòu)造一個(gè)新的Python對象!

   15.17.1.20。可變大小的數(shù)據(jù)類型

ctypes 為可變大小的數(shù)組和結(jié)構(gòu)提供了一些支持。

resize()函數(shù)可用于調(diào)整現(xiàn)有ctypes對象的內(nèi)存緩沖區(qū)的大小。該函數(shù)將對象作為第一個(gè)參數(shù),并將請求的大?。ㄒ宰止?jié)為單位)作為第二個(gè)參數(shù)。內(nèi)存塊不能小于對象類型指定的自然內(nèi)存塊,ValueError如果嘗試,則引發(fā)a :

  1. >>> short_array = (c_short * 4)()
  2. >>> print sizeof(short_array)
  3. 8
  4. >>> resize(short_array, 4)
  5. Traceback (most recent call last):
  6. ...
  7. ValueError: minimum size is 8
  8. >>> resize(short_array, 32)
  9. >>> sizeof(short_array)
  10. 32
  11. >>> sizeof(type(short_array))
  12. 8
  13. >>>

這很好很好,但是如何訪問此數(shù)組中包含的其他元素?由于類型仍然只知道4個(gè)元素,因此訪問其他元素時(shí)會(huì)出錯(cuò):

  1. >>> short_array[:]
  2. [0, 0, 0, 0]
  3. >>> short_array[7]
  4. Traceback (most recent call last):
  5. ...
  6. IndexError: invalid index
  7. >>>

使用可變大小數(shù)據(jù)類型的另一種方法ctypes是使用Python的動(dòng)態(tài)特性,并且在已知所需大小之后(根據(jù)具體情況)重新定義數(shù)據(jù)類型。

  15.17.2。ctypes引用

  15.17.2.1。查找共享庫

使用編譯語言編程時(shí),在編譯/鏈接程序時(shí)以及程序運(yùn)行時(shí)都會(huì)訪問共享庫。

find_library()函數(shù)的目的是以類似于編譯器的方式定位庫(在具有多個(gè)版本的共享庫的平臺(tái)上應(yīng)該加載最新版本),而ctypes庫加載器就像程序運(yùn)行時(shí)一樣,并直接調(diào)用運(yùn)行時(shí)加載程序。

ctypes.util模塊提供了一個(gè)函數(shù),可以幫助確定要加載的庫。

ctypes.util.find_library姓名

嘗試查找?guī)觳⒎祷芈窂矫?nbsp;名字是不一樣的任何前綴庫名的lib,標(biāo)的相同.so,.dylib或版本號(hào)(這是用于POSIX鏈接器選項(xiàng)的形式-l)。如果找不到庫,則返回None。

確切的功能取決于系統(tǒng)。

在Linux上,find_library()嘗試運(yùn)行外部程序(/sbin/ldconfiggcc,和objdump)找到庫文件。它返回庫文件的文件名。這里有些例子:

  1. >>> from ctypes.util import find_library
  2. >>> find_library("m")
  3. 'libm.so.6'
  4. >>> find_library("c")
  5. 'libc.so.6'
  6. >>> find_library("bz2")
  7. 'libbz2.so.1.0'
  8. >>>

在OS X上,find_library()嘗試幾個(gè)預(yù)定義的命名方案和路徑來定位庫,如果成功則返回完整路徑名:

  1. >>> from ctypes.util import find_library
  2. >>> find_library("c")
  3. '/usr/lib/libc.dylib'
  4. >>> find_library("m")
  5. '/usr/lib/libm.dylib'
  6. >>> find_library("bz2")
  7. '/usr/lib/libbz2.dylib'
  8. >>> find_library("AGL")
  9. '/System/Library/Frameworks/AGL.framework/AGL'
  10. >>>

在Windows上,find_library()沿系統(tǒng)搜索路徑進(jìn)行搜索,并返回完整路徑名,但由于沒有預(yù)定義的命名方案,因此調(diào)用find_library("c")將失敗并返回None。

如果包裝共享庫ctypes,它可以更好地確定在開發(fā)時(shí)共享庫的名字,并硬編碼到封裝模塊,而不是使用find_library()定位在運(yùn)行時(shí)庫。

   15.17.2.2。加載共享庫

有幾種方法可以將共享庫加載到Python進(jìn)程中。一種方法是實(shí)例化以下類之一:

class ctypes.CDLLname,mode = DEFAULT_MODE,handle = None,use_errno = False,use_last_error = False 

此類的實(shí)例表示已加載的共享庫。這些庫中的函數(shù)使用標(biāo)準(zhǔn)C調(diào)用約定,并假定返回 int。

class ctypes.OleDLLname,mode = DEFAULT_MODEhandle = None,use_errno = Falseuse_last_error = False 

僅限Windows:此類的實(shí)例表示已加載的共享庫,這些庫中的函數(shù)使用stdcall調(diào)用約定,并假定返回特定于Windows的HRESULT代碼。 HRESULT values包含指定函數(shù)調(diào)用是否失敗或成功的信息,以及其他錯(cuò)誤代碼。如果返回值表示失敗,WindowsError則自動(dòng)引發(fā)a。

class ctypes.WinDLLname,mode = DEFAULT_MODEhandle = None,use_errno = False,use_last_error = False 

僅限Windows:此類的實(shí)例表示已加載的共享庫,這些庫中的函數(shù)使用stdcall調(diào)用約定,并且int默認(rèn)情況下假定返回。

在Windows CE上,僅使用標(biāo)準(zhǔn)調(diào)用約定,以方便 WinDLLOleDLL使用此平臺(tái)上的標(biāo)準(zhǔn)調(diào)用約定。

Python 全局解釋器鎖在調(diào)用這些庫導(dǎo)出的任何函數(shù)之前發(fā)布,之后重新獲取。

class ctypes.PyDLLname,mode = DEFAULT_MODE,handle = None 

CDLL除了在函數(shù)調(diào)用期間釋放Python GIL之外,此類的實(shí)例的行為與實(shí)例類似,并且在函數(shù)執(zhí)行之后,將檢查Python錯(cuò)誤標(biāo)志。如果設(shè)置了錯(cuò)誤標(biāo)志,則會(huì)引發(fā)Python異常。

因此,這僅對直接調(diào)用Python C api函數(shù)有用。

所有這些類都可以通過使用至少一個(gè)參數(shù)(共享庫的路徑名)調(diào)用它們來實(shí)例化。如果已有已加載的共享庫的現(xiàn)有句柄,則可以將其作為handle命名參數(shù)傳遞,否則使用基礎(chǔ)平臺(tái)dlopenLoadLibrary 函數(shù)將庫加載到進(jìn)程中,并獲取它的句柄。

模式參數(shù)可用于指定庫的加載方式。有關(guān)詳細(xì)信息,請參閱dlopen(3)聯(lián)機(jī)幫助頁。在Windows上,模式被忽略。在posix系統(tǒng)上,始終添加RTLD_NOW,并且不可配置。

use_errno參數(shù),當(dāng)設(shè)置為true,使一個(gè)ctypes機(jī)制,允許訪問該系統(tǒng)errno以安全的方式錯(cuò)誤號(hào)。 ctypes維護(hù)系統(tǒng)errno 變量的線程局部副本; 如果在函數(shù)調(diào)用與ctypes私有副本交換之前調(diào)用用函數(shù)調(diào)用創(chuàng)建的外部函數(shù),use_errno=True則在 errno函數(shù)調(diào)用之后立即發(fā)生相同的操作。

該函數(shù)ctypes.get_errno()返回ctypes私有副本的值,該函數(shù)將ctypes私有副本ctypes.set_errno()更改為新值并返回前一個(gè)值。

use_last_error參數(shù),設(shè)置為true時(shí),使能由所述管理Windows錯(cuò)誤代碼相同的機(jī)制GetLastError()和 SetLastError()Windows API函數(shù); ctypes.get_last_error()并 ctypes.set_last_error()用于請求和更改Windows錯(cuò)誤代碼的ctypes私有副本。

新的2.6版:use_last_erroruse_errno可選參數(shù)添加。

ctypes.RTLD_GLOBAL

用作模式參數(shù)的標(biāo)志。在此標(biāo)志不可用的平臺(tái)上,它被定義為整數(shù)零。

ctypes.RTLD_LOCAL

用作模式參數(shù)的標(biāo)志。在沒有此功能的平臺(tái)上,它與RTLD_GLOBAL相同。

ctypes.DEFAULT_MODE

用于加載共享庫的默認(rèn)模式。在OSX 10.3上,這是 RTLD_GLOBAL,否則它與RTLD_LOCAL相同。

這些類的實(shí)例沒有公共方法。共享庫導(dǎo)出的函數(shù)可以作為屬性或索引進(jìn)行訪問。請注意,通過屬性訪問函數(shù)會(huì)緩存結(jié)果,因此每次重復(fù)訪問它都會(huì)返回相同的對象。另一方面,通過索引訪問它每次都會(huì)返回一個(gè)新對象:

  1. >>> libc.time == libc.time
  2. True
  3. >>> libc['time'] == libc['time']
  4. False

可以使用以下公共屬性,它們的名稱以下劃線開頭,以便不與導(dǎo)出的函數(shù)名沖突:

PyDLL._handle

用于訪問庫的系統(tǒng)句柄。

PyDLL._name

在構(gòu)造函數(shù)中傳遞的庫的名稱。

還可以使用其中一個(gè)預(yù)制對象(LibraryLoader通過調(diào)用 LoadLibrary()方法)或通過將庫檢索為加載程序?qū)嵗膶傩詠砑虞d共享庫。

class ctypes.LibraryLoaderdlltype 

加載共享庫的類。 dlltype應(yīng)該是一個(gè) CDLLPyDLL,WinDLLOleDLL類型。

__getattr__()具有特殊行為:它允許通過將其作為庫加載器實(shí)例的屬性訪問來加載共享庫。結(jié)果是緩存的,因此重復(fù)的屬性訪問每次都返回相同的庫。

LoadLibrary名字

將共享庫加載到進(jìn)程中并返回它。此方法始終返回庫的新實(shí)例。

這些預(yù)制庫加載器可用:

ctypes.cdll

創(chuàng)建CDLL實(shí)例。

ctypes.windll

僅限Windows:創(chuàng)建WinDLL實(shí)例。

ctypes.oledll

僅限Windows:創(chuàng)建OleDLL實(shí)例。

ctypes.pydll

創(chuàng)建PyDLL實(shí)例。

為了直接訪問C Python api,可以使用現(xiàn)成的Python共享庫對象:

ctypes.pythonapi

它的一個(gè)實(shí)例PyDLL將Python C API函數(shù)公開為屬性。請注意,假設(shè)所有這些函數(shù)都返回C int,這當(dāng)然不總是事實(shí),因此您必須分配正確的restype屬性才能使用這些函數(shù)。

   15.17.2.3。外來函數(shù)

如前一節(jié)所述,外部函數(shù)可以作為加載的共享庫的屬性進(jìn)行訪問。默認(rèn)情況下以這種方式創(chuàng)建的函數(shù)對象接受任意數(shù)量的參數(shù),接受任何ctypes數(shù)據(jù)實(shí)例作為參數(shù),并返回庫加載器指定的默認(rèn)結(jié)果類型。他們是私人班級的實(shí)例:

ctypes._FuncPtr

C可調(diào)用外部函數(shù)的基類。

外部函數(shù)的實(shí)例也是C兼容的數(shù)據(jù)類型; 它們代表C函數(shù)指針。

可以通過分配外部函數(shù)對象的特殊屬性來自定義此行為。

restype

指定ctypes類型以指定外部函數(shù)的結(jié)果類型。使用Nonevoid,功能不返回任何東西。

可以分配不是ctypes類型的可調(diào)用Python對象,在這種情況下假定函數(shù)返回C int,并且將使用此整數(shù)調(diào)用callable,從而允許進(jìn)一步處理或錯(cuò)誤檢查。不推薦使用它,為了更靈活的后處理或錯(cuò)誤檢查,請使用ctypes數(shù)據(jù)類型, restype并為該errcheck屬性分配一個(gè)callable 。

argtypes

分配ctypes類型的元組以指定函數(shù)接受的參數(shù)類型。使用stdcall調(diào)用約定的函數(shù)只能使用與此元組的長度相同的參數(shù)數(shù)來調(diào)用; 使用C調(diào)用約定的函數(shù)也接受其他未指定的參數(shù)。

當(dāng)調(diào)用外部函數(shù)時(shí),每個(gè)實(shí)際參數(shù)都傳遞給 元組中from_param()項(xiàng)的 類方法argtypes,此方法允許將實(shí)際參數(shù)調(diào)整為外部函數(shù)接受的對象。例如,元組中的c_char_p項(xiàng)argtypes將使用ctypes轉(zhuǎn)換規(guī)則將作為參數(shù)傳遞的unicode字符串轉(zhuǎn)換為字節(jié)字符串。

新增:現(xiàn)在可以將項(xiàng)目放在不是ctypes類型的argtypes中,但每個(gè)項(xiàng)目必須有一個(gè)from_param()返回可用作參數(shù)的值的方法(整數(shù),字符串,ctypes實(shí)例)。這允許定義可以將自定義對象調(diào)整為函數(shù)參數(shù)的適配器。

errcheck

為此屬性分配Python函數(shù)或其他可調(diào)用函數(shù)。將使用三個(gè)或更多參數(shù)調(diào)用callable:

callable結(jié)果函數(shù),參數(shù)

result是外部函數(shù)返回的內(nèi)容,由restype屬性指定 。

func是外部函數(shù)對象本身,這允許重用相同的可調(diào)用對象來檢查或后處理幾個(gè)函數(shù)的結(jié)果。

arguments是一個(gè)包含最初傳遞給函數(shù)調(diào)用的參數(shù)的元組,這允許對所使用的參數(shù)進(jìn)行特殊處理。

此函數(shù)返回的對象將從外部函數(shù)調(diào)用返回,但如果外部函數(shù)調(diào)用失敗,它還可以檢查結(jié)果值并引發(fā)異常。

異常ctypes.ArgumentError

當(dāng)外部函數(shù)調(diào)用無法轉(zhuǎn)換其中一個(gè)傳遞的參數(shù)時(shí),會(huì)引發(fā)此異常。

   15.17.2.4。函數(shù)原型

也可以通過實(shí)例化函數(shù)原型來創(chuàng)建外部函數(shù)。函數(shù)原型類似于C中的函數(shù)原型; 它們描述了一個(gè)函數(shù)(返回類型,參數(shù)類型,調(diào)用約定)而沒有定義實(shí)現(xiàn)。必須使用所需的結(jié)果類型和函數(shù)的參數(shù)類型調(diào)用工廠函數(shù)。

ctypes.CFUNCTYPErestype,* argtypesuse_errno = False,use_last_error = False 

返回的函數(shù)原型創(chuàng)建使用標(biāo)準(zhǔn)C調(diào)用約定的函數(shù)。該功能將在通話期間釋放GIL。如果 use_errno設(shè)置為true,則系統(tǒng)errno變量的ctypes私有副本將 與errno調(diào)用前后的實(shí)際值進(jìn)行交換; use_last_error對Windows錯(cuò)誤代碼執(zhí)行相同操作。

版本2.6中已更改:添加了可選的use_errnouse_last_error參數(shù)。

ctypes.WINFUNCTYPErestype,* argtypes,use_errno = False,use_last_error = False 

僅適用于Windows:返回的函數(shù)原型創(chuàng)建使用函數(shù) stdcall調(diào)用約定,除了Windows CE地方 WINFUNCTYPE()是一樣的CFUNCTYPE()。該功能將在通話期間釋放GIL。 use_errnouse_last_error具有與上面相同的含義。

ctypes.PYFUNCTYPErestype* argtypes 

返回的函數(shù)原型創(chuàng)建使用Python調(diào)用約定的函數(shù)。該功能在通話期間不會(huì)釋放GIL。

由這些工廠函數(shù)創(chuàng)建的函數(shù)原型可以以不同的方式實(shí)例化,具體取決于調(diào)用中參數(shù)的類型和數(shù)量:

prototype地址

返回指定地址的外部函數(shù),該函數(shù)必須是整數(shù)。

prototype可贖回

從Python 可調(diào)用創(chuàng)建C可調(diào)用函數(shù)(回調(diào)函數(shù))。

prototypefunc_spec [,paramflags ] )

返回由共享庫導(dǎo)出的外部函數(shù)。func_spec必須是2元組。第一項(xiàng)是導(dǎo)出函數(shù)的名稱作為字符串,或?qū)С龊瘮?shù)的序號(hào)作為小整數(shù)。第二項(xiàng)是共享庫實(shí)例。(name_or_ordinal, library)

prototypevtbl_index,name [,paramflags [,iid ] ] )

返回將調(diào)用COM方法的外部函數(shù)。vtbl_index是虛函數(shù)表的索引,是一個(gè)小的非負(fù)整數(shù)。name是COM方法的名稱。iid是指向擴(kuò)展錯(cuò)誤報(bào)告中使用的接口標(biāo)識(shí)符的可選指針。

COM方法使用特殊的調(diào)用約定:除了argtypes元組中指定的那些參數(shù)外,它們還需要指向COM接口的指針作為第一個(gè)參數(shù)。

可選的paramflags參數(shù)創(chuàng)建的外部函數(shù)包裝器具有比上述功能更多的功能。

paramflags必須是一個(gè)長度相同的元組argtypes

此元組中的每個(gè)項(xiàng)目都包含有關(guān)參數(shù)的更多信息,它必須是包含一個(gè),兩個(gè)或三個(gè)項(xiàng)目的元組。

第一項(xiàng)是一個(gè)整數(shù),包含參數(shù)的方向標(biāo)志組合:

1

指定函數(shù)的輸入?yún)?shù)。

2

輸出參數(shù)。外來函數(shù)填入一個(gè)值。

4

輸入?yún)?shù),默認(rèn)為整數(shù)零。

可選的第二項(xiàng)是參數(shù)名稱為字符串。如果指定了此參數(shù),則可以使用命名參數(shù)調(diào)用外部函數(shù)。

可選的第三項(xiàng)是此參數(shù)的默認(rèn)值。

此示例演示如何包裝Windows MessageBoxA函數(shù),以便它支持默認(rèn)參數(shù)和命名參數(shù)。Windows頭文件中的C聲明是這樣的:

  1. WINUSERAPI int WINAPI
  2. MessageBoxA(
  3. HWND hWnd,
  4. LPCSTR lpText,
  5. LPCSTR lpCaption,
  6. UINT uType);

這是包裝ctypes

  1. >>> from ctypes import c_int, WINFUNCTYPE, windll
  2. >>> from ctypes.wintypes import HWND, LPCSTR, UINT
  3. >>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
  4. >>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
  5. >>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)
  6. >>>

現(xiàn)在可以通過以下方式調(diào)用MessageBox外部函數(shù):

  1. >>> MessageBox()
  2. >>> MessageBox(text="Spam, spam, spam")
  3. >>> MessageBox(flags=2, text="foo bar")
  4. >>>

第二個(gè)例子演示了輸出參數(shù)。win32 GetWindowRect 函數(shù)通過將指定窗口的尺寸復(fù)制到RECT調(diào)用者必須提供的結(jié)構(gòu)中來檢索它們的尺寸 。這是C聲明:

  1. WINUSERAPI BOOL WINAPI
  2. GetWindowRect(
  3. HWND hWnd,
  4. LPRECT lpRect);

這是包裝ctypes

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

具有輸出參數(shù)的函數(shù)將自動(dòng)返回輸出參數(shù)值(如果存在單個(gè)參數(shù)值)或者包含輸出參數(shù)值的元組(如果有多個(gè)),則GetWindowRect函數(shù)現(xiàn)在會(huì)在調(diào)用時(shí)返回RECT實(shí)例。

輸出參數(shù)可以與errcheck協(xié)議組合以進(jìn)行進(jìn)一步的輸出處理和錯(cuò)誤檢查。win32 GetWindowRectapi函數(shù)返回一個(gè)BOOL指示成功或失敗的信號(hào),因此該函數(shù)可以執(zhí)行錯(cuò)誤檢查,并在api調(diào)用失敗時(shí)引發(fā)異常:

  1. >>> def errcheck(result, func, args):
  2. ... if not result:
  3. ... raise WinError()
  4. ... return args
  5. ...
  6. >>> GetWindowRect.errcheck = errcheck
  7. >>>

如果errcheck函數(shù)返回參數(shù)tuple,它接收不變,ctypes繼續(xù)對輸出參數(shù)進(jìn)行的正常處理。如果要返回窗口坐標(biāo)而不是RECT實(shí)例的元組 ,可以檢索函數(shù)中的字段并返回它們,將不再進(jìn)行正常處理:

  1. >>> def errcheck(result, func, args):
  2. ... if not result:
  3. ... raise WinError()
  4. ... rc = args[1]
  5. ... return rc.left, rc.top, rc.bottom, rc.right
  6. ...
  7. >>> GetWindowRect.errcheck = errcheck
  8. >>>

   15.17.2.5。實(shí)用功能

ctypes.addressofobj 

以整數(shù)形式返回內(nèi)存緩沖區(qū)的地址。 obj必須是ctypes類型的實(shí)例。

ctypes.alignmentobj_or_type 

返回ctypes類型的對齊要求。obj_or_type必須是ctypes類型或?qū)嵗?/p>

ctypes.byrefobj [,offset ] )

返回一個(gè)指向obj的輕量級指針,該指針必須是ctypes類型的一個(gè)實(shí)例。 offset默認(rèn)為零,并且必須是將添加到內(nèi)部指針值的整數(shù)。

byref(obj, offset) 對應(yīng)于此C代碼:

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

返回的對象只能用作外部函數(shù)調(diào)用參數(shù)。它的行為類似pointer(obj),但構(gòu)造速度要快得多。

:在2.6版本中的新偏移添加可選的參數(shù)。

ctypes.castobj,type 

此函數(shù)類似于C中的強(qiáng)制轉(zhuǎn)換運(yùn)算符。它返回一個(gè)新的類型實(shí)例,它指向與obj相同的內(nèi)存塊。 type 必須是指針類型,obj必須是可以解釋為指針的對象。

ctypes.create_string_bufferinit_or_size [,size ] )

此函數(shù)創(chuàng)建一個(gè)可變字符緩沖區(qū)。返回的對象是ctypes數(shù)組c_char。

init_or_size必須是一個(gè)整數(shù),它指定數(shù)組的大小,或者是一個(gè)用于初始化數(shù)組項(xiàng)的字符串。

如果將字符串指定為第一個(gè)參數(shù),則將緩沖區(qū)設(shè)置為大于字符串長度的一個(gè)項(xiàng)目,以便數(shù)組中的最后一個(gè)元素是NUL終止字符??梢詫⒄麛?shù)作為第二個(gè)參數(shù)傳遞,如果不應(yīng)使用字符串的長度,則允許指定數(shù)組的大小。

如果第一個(gè)參數(shù)是unicode字符串,則根據(jù)ctypes轉(zhuǎn)換規(guī)則將其轉(zhuǎn)換為8位字符串。

ctypes.create_unicode_bufferinit_or_size [,size ] )

此函數(shù)創(chuàng)建一個(gè)可變的unicode字符緩沖區(qū)。返回的對象是ctypes數(shù)組c_wchar

init_or_size必須是指定數(shù)組大小的整數(shù),或者是用于初始化數(shù)組項(xiàng)的unicode字符串。

如果將unicode字符串指定為第一個(gè)參數(shù),則將緩沖區(qū)設(shè)置為大于字符串長度的一個(gè)項(xiàng)目,以便數(shù)組中的最后一個(gè)元素是NUL終止字符??梢詫⒄麛?shù)作為第二個(gè)參數(shù)傳遞,如果不應(yīng)使用字符串的長度,則允許指定數(shù)組的大小。

如果第一個(gè)參數(shù)是8位字符串,則根據(jù)ctypes轉(zhuǎn)換規(guī)則將其轉(zhuǎn)換為unicode字符串。

ctypes.DllCanUnloadNow()

僅限Windows:此函數(shù)是一個(gè)鉤子,允許使用ctypes實(shí)現(xiàn)進(jìn)程內(nèi)COM服務(wù)器。從DllCanUnloadNow函數(shù)調(diào)用_ctypes擴(kuò)展dll導(dǎo)出。

ctypes.DllGetClassObject()

僅限Windows:此函數(shù)是一個(gè)鉤子,允許使用ctypes實(shí)現(xiàn)進(jìn)程內(nèi)COM服務(wù)器。它是從_ctypes擴(kuò)展dll導(dǎo)出的DllGetClassObject函數(shù)調(diào)用的。

ctypes.util.find_library名字

嘗試查找?guī)觳⒎祷芈窂矫?nbsp;name是沒有任何前綴的庫名,如lib后綴.so.dylib或版本號(hào)(這是用于posix鏈接器選項(xiàng)的形式-l)。如果找不到庫,則返回None。

確切的功能取決于系統(tǒng)。

在版本2.6中更改:僅限Windows:find_library("m")find_library("c")將調(diào)用的結(jié)果返回到find_msvcrt()。

ctypes.util.find_msvcrt()

僅限Windows:返回Python使用的VC運(yùn)行時(shí)庫的文件名,以及擴(kuò)展模塊。如果無法確定庫的名稱,None則返回。

如果需要釋放內(nèi)存,例如,由擴(kuò)展模塊調(diào)用的內(nèi)存,則必須在分配內(nèi)存的同一庫中使用該功能。free(void *)

版本2.6中的新功能。

ctypes.FormatError([ code ] )

僅適用于Windows:返回的錯(cuò)誤代碼的文本描述代碼。如果未指定錯(cuò)誤代碼,則通過調(diào)用Windows api函數(shù)GetLastError來使用上一個(gè)錯(cuò)誤代碼。

ctypes.GetLastError()

僅限Windows:返回Windows在調(diào)用線程中設(shè)置的最后一個(gè)錯(cuò)誤代碼。此函數(shù)直接調(diào)用Windows GetLastError()函數(shù),它不返回錯(cuò)誤代碼的ctypes-private副本。

ctypes.get_errno()

返回errno調(diào)用線程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值 。

版本2.6中的新功能。

ctypes.get_last_error()

僅限Windows:返回LastError調(diào)用線程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值 。

版本2.6中的新功能。

ctypes.memmovedstsrc,count 

與標(biāo)準(zhǔn)C memmove庫函數(shù)相同:將計(jì)數(shù)字節(jié)從 src復(fù)制到dstdstsrc必須是可以轉(zhuǎn)換為指針的整數(shù)或ctypes實(shí)例。

ctypes.memsetdst,ccount 

與標(biāo)準(zhǔn)C memset庫函數(shù)相同:使用值c的計(jì)數(shù)字節(jié)填充地址dst處的內(nèi)存塊。dst必須是指定地址的整數(shù)或ctypes實(shí)例。

ctypes.POINTER類型

此工廠函數(shù)創(chuàng)建并返回新的ctypes指針類型。指針類型在內(nèi)部被緩存和重用,因此重復(fù)調(diào)用此函數(shù)很便宜。type必須是ctypes類型。

ctypes.pointerobj 

此函數(shù)創(chuàng)建一個(gè)指向obj的新指針實(shí)例。返回的對象屬于該類型POINTER(type(obj))。

注意:如果您只想將指向?qū)ο蟮闹羔槀鬟f給外部函數(shù)調(diào)用,則應(yīng)該使用byref(obj)哪個(gè)更快。

ctypes.resizeobj,size 

此函數(shù)調(diào)整obj的內(nèi)部內(nèi)存緩沖區(qū)的大小,obj必須是ctypes類型的實(shí)例。如下所示,不可能使緩沖區(qū)小于對象類型的本機(jī)大小sizeof(type(obj)),但可以放大緩沖區(qū)。

ctypes.set_conversion_mode編碼錯(cuò)誤

此函數(shù)設(shè)置ctypes對象在8位字符串和unicode字符串之間進(jìn)行轉(zhuǎn)換時(shí)使用的規(guī)則。 encoding必須是指定編碼的字符串,如'utf-8''mbcs',錯(cuò)誤必須是一個(gè)字符串,指定編碼/解碼錯(cuò)誤的錯(cuò)誤處理??赡艿闹档膶?shí)例是"strict","replace",或"ignore"。

set_conversion_mode()返回包含先前轉(zhuǎn)換規(guī)則的2元組。在Windows上,初始轉(zhuǎn)換規(guī)則在其他系統(tǒng)上。('mbcs', 'ignore')('ascii', 'strict')

ctypes.set_errno

errno 調(diào)用線程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值設(shè)置為value并返回先前的值。

版本2.6中的新功能。

ctypes.set_last_error

僅限Windows:將LastError調(diào)用線程中系統(tǒng)變量的ctypes-private副本的當(dāng)前值設(shè)置 為value并返回先前的值。

版本2.6中的新功能。

ctypes.sizeofobj_or_type 

返回ctypes類型或?qū)嵗齼?nèi)存緩沖區(qū)的大?。ㄒ宰止?jié)為單位)。與C sizeof運(yùn)算符相同。

ctypes.string_at地址[,大小] )

這個(gè)函數(shù)返回了從內(nèi)存地址字符串地址。如果指定了size,則將其用作size,否則假定該字符串為零終止。

ctypes.WinErrorcode = None,descr = None 

僅限Windows:此函數(shù)可能是ctypes中最糟糕的名稱。它創(chuàng)建了一個(gè)WindowsError實(shí)例。如果未指定代碼, GetLastError則調(diào)用以確定錯(cuò)誤代碼。如果descr未指定,FormatError()則調(diào)用以獲取錯(cuò)誤的文本描述。

ctypes.wstring_at地址[,大小] )

這個(gè)函數(shù)返回了從內(nèi)存地址寬字符串 地址為unicode字符串。如果指定了size,則將其用作字符串的字符數(shù),否則假定該字符串為零終止。

   15.17.2.6。數(shù)據(jù)類型

ctypes._CData

這個(gè)非公共類是所有ctypes數(shù)據(jù)類型的公共基類。除此之外,所有ctypes類型實(shí)例都包含一個(gè)保存C兼容數(shù)據(jù)的內(nèi)存塊; addressof()輔助函數(shù)返回內(nèi)存塊的地址 。另一個(gè)實(shí)例變量暴露為 _objects; 這包含其他需要保持活動(dòng)的Python對象,以防內(nèi)存塊包含指針。

ctypes數(shù)據(jù)類型的常用方法,這些都是類方法(確切地說,它們是元類的方法):

from_buffer來源[,偏移] )

此方法返回共享對象的緩沖區(qū)的ctypes實(shí)例 。所述對象必須支持可寫緩沖器接口??蛇x的offset參數(shù)指定源緩沖區(qū)的偏移量(以字節(jié)為單位); 默認(rèn)值為零。如果源緩沖區(qū)不夠大,ValueError則會(huì)引發(fā)a。

版本2.6中的新功能。

from_buffer_copy來源[,偏移] )

此方法創(chuàng)建一個(gè)ctypes實(shí)例,從對象緩沖區(qū)復(fù)制緩沖區(qū),該 緩沖區(qū)必須是可讀的。可選的offset 參數(shù)指定源緩沖區(qū)的偏移量(以字節(jié)為單位); 默認(rèn)值為零。如果源緩沖區(qū)不夠大,ValueError則會(huì)引發(fā)a。

版本2.6中的新功能。

from_address地址

此方法使用address指定的內(nèi)存返回ctypes類型實(shí)例,該內(nèi)存 必須是整數(shù)。

from_paramobj 

此方法使obj適應(yīng)ctypes類型。當(dāng)外部函數(shù)的argtypes元組中存在類型時(shí),使用外部函數(shù)調(diào)用中使用的實(shí)際對象調(diào)用它; 它必須返回一個(gè)可以用作函數(shù)調(diào)用參數(shù)的對象。

所有ctypes數(shù)據(jù)類型都具有此類方法的默認(rèn)實(shí)現(xiàn),如果是類型的實(shí)例,則通常返回obj。某些類型也接受其他對象。

in_dll圖書館,名稱

此方法返回由共享庫導(dǎo)出的ctypes類型實(shí)例。name是導(dǎo)出數(shù)據(jù)的符號(hào)的名稱,library 是加載的共享庫。

ctypes數(shù)據(jù)類型的常見實(shí)例變量:

_b_base_

有時(shí)ctypes數(shù)據(jù)實(shí)例不擁有它們包含的內(nèi)存塊,而是共享基礎(chǔ)對象的部分內(nèi)存塊。所述 _b_base_只讀構(gòu)件是根ctypes的對象擁有該存儲(chǔ)器塊。

_b_needsfree_

當(dāng)ctypes數(shù)據(jù)實(shí)例已分配內(nèi)存塊本身時(shí),此只讀變量為true,否則為false。

_objects

該成員None或者是包含需要保持活動(dòng)的Python對象的字典,以便內(nèi)存塊內(nèi)容保持有效。該對象僅用于調(diào)試; 永遠(yuǎn)不要修改這本詞典的內(nèi)容。

   15.17.2.7?;緮?shù)據(jù)類型

ctypes._SimpleCData

這個(gè)非公共類是所有基本ctypes數(shù)據(jù)類型的基類。這里提到它是因?yàn)樗綾types數(shù)據(jù)類型的公共屬性。 _SimpleCData是它的子類 _CData,因此它繼承了它們的方法和屬性。

在版本2.6中更改:現(xiàn)在可以對不包含指針但不包含指針的ctypes數(shù)據(jù)類型進(jìn)行pickle。

實(shí)例具有單個(gè)屬性:

value

該屬性包含實(shí)例的實(shí)際值。對于整數(shù)和指針類型,它是一個(gè)整數(shù),對于字符類型,它是單個(gè)字符串,對于字符指針類型,它是Python字符串或unicode字符串。

當(dāng)value屬性從一個(gè)ctypes實(shí)例獲取,通常是一個(gè)新的對象,每次返回。 ctypes沒有實(shí)現(xiàn)原來的目標(biāo)回報(bào)率,總是一個(gè)新的對象被創(chuàng)建。所有其他ctypes對象實(shí)例也是如此。

基本數(shù)據(jù)類型作為外部函數(shù)調(diào)用結(jié)果返回時(shí),或者例如通過檢索結(jié)構(gòu)字段成員或數(shù)組項(xiàng),將透明地轉(zhuǎn)換為本機(jī)Python類型。換句話說,如果一個(gè)外國函數(shù)有一個(gè) restypec_char_p,你總是會(huì)收到一個(gè)Python字符串, 不是一個(gè)c_char_p實(shí)例。

基本數(shù)據(jù)類型的子類不會(huì)繼承此行為。因此,如果外部函數(shù)restype是其子類c_void_p,您將從函數(shù)調(diào)用中接收此子類的實(shí)例。當(dāng)然,您可以通過訪問value屬性來獲取指針的值。

這些是基本的ctypes數(shù)據(jù)類型:

ctypes.c_byte

表示C 數(shù)據(jù)類型,并將該值解釋為小整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。signed char

ctypes.c_char

表示C char數(shù)據(jù)類型,并將該值解釋為單個(gè)字符。構(gòu)造函數(shù)接受可選的字符串初始值設(shè)定項(xiàng),字符串的長度必須恰好是一個(gè)字符。

ctypes.c_char_p

當(dāng)它指向以零結(jié)尾的字符串時(shí)表示C 數(shù)據(jù)類型。對于也可能指向二進(jìn)制數(shù)據(jù)的通用字符指針, 必須使用。構(gòu)造函數(shù)接受整數(shù)地址或字符串。char *POINTER(c_char)

ctypes.c_double

表示C double數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的float初始化程序。

ctypes.c_longdouble

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的float初始化程序。在它是別名的平臺(tái)上。long doublesizeof(long double) == sizeof(double)c_double

版本2.6中的新功能。

ctypes.c_float

表示C float數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的float初始化程序。

ctypes.c_int

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。在它是別名的平臺(tái)上。signed intsizeof(int) == sizeof(long)c_long

ctypes.c_int8

表示C 8位數(shù)據(jù)類型。通常是別名 。signed intc_byte

ctypes.c_int16

表示C 16位數(shù)據(jù)類型。通常是別名 。signed intc_short

ctypes.c_int32

表示C 32位數(shù)據(jù)類型。通常是別名 。signed intc_int

ctypes.c_int64

表示C 64位數(shù)據(jù)類型。通常是別名 。signed intc_longlong

ctypes.c_long

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。signed long

ctypes.c_longlong

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。signed long long

ctypes.c_short

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。signed short

ctypes.c_size_t

表示C size_t數(shù)據(jù)類型。

ctypes.c_ssize_t

表示C ssize_t數(shù)據(jù)類型。

版本2.7中的新功能。

ctypes.c_ubyte

表示C 數(shù)據(jù)類型,它將值解釋為小整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。unsigned char

ctypes.c_uint

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。在它是別名的平臺(tái)上。unsigned intsizeof(int) == sizeof(long)c_ulong

ctypes.c_uint8

表示C 8位數(shù)據(jù)類型。通常是別名 。unsigned intc_ubyte

ctypes.c_uint16

表示C 16位數(shù)據(jù)類型。通常是別名 。unsigned intc_ushort

ctypes.c_uint32

表示C 32位數(shù)據(jù)類型。通常是別名 。unsigned intc_uint

ctypes.c_uint64

表示C 64位數(shù)據(jù)類型。通常是別名 。unsigned intc_ulonglong

ctypes.c_ulong

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。unsigned long

ctypes.c_ulonglong

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。unsigned long long

ctypes.c_ushort

表示C 數(shù)據(jù)類型。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng); 沒有進(jìn)行溢出檢查。unsigned short

ctypes.c_void_p

表示C 類型。該值表示為整數(shù)。構(gòu)造函數(shù)接受可選的整數(shù)初始值設(shè)定項(xiàng)。void *

ctypes.c_wchar

表示C wchar_t數(shù)據(jù)類型,并將該值解釋為單個(gè)字符的unicode字符串。構(gòu)造函數(shù)接受可選的字符串初始值設(shè)定項(xiàng),字符串的長度必須恰好是一個(gè)字符。

ctypes.c_wchar_p

表示C 數(shù)據(jù)類型,該數(shù)據(jù)類型必須是指向以零結(jié)尾的寬字符串的指針。構(gòu)造函數(shù)接受整數(shù)地址或字符串。wchar_t *

ctypes.c_bool

表示C bool數(shù)據(jù)類型(更準(zhǔn)確地說,_Bool來自C99)。它的值可以是True或者False,構(gòu)造函數(shù)接受任何具有真值的對象。

版本2.6中的新功能。

ctypes.HRESULT

僅限Windows:表示一個(gè)HRESULT值,其中包含函數(shù)或方法調(diào)用的成功或錯(cuò)誤信息。

ctypes.py_object

表示C 數(shù)據(jù)類型。在沒有參數(shù)的情況下調(diào)用它會(huì)創(chuàng)建一個(gè)指針。PyObject *NULL PyObject *

ctypes.wintypes模塊提供了相當(dāng)長的一段其他Windows特定的數(shù)據(jù)類型,例如HWND,WPARAMDWORD。一些有用的結(jié)構(gòu),如MSGRECT定義。

   15.17.2.8。結(jié)構(gòu)化數(shù)據(jù)類型

class ctypes.Union* args** kw 

原始字節(jié)順序的聯(lián)合的抽象基類。

class ctypes.BigEndianStructure* args** kw 

大端字節(jié)順序結(jié)構(gòu)的抽象基類。

class ctypes.LittleEndianStructure* args,** kw 

小端字節(jié)順序結(jié)構(gòu)的抽象基類。

具有非本機(jī)字節(jié)順序的結(jié)構(gòu)不能包含指針類型字段或包含指針類型字段的任何其他數(shù)據(jù)類型。

class ctypes.Structure* args,** kw 

本機(jī)字節(jié)順序的結(jié)構(gòu)的抽象基類。

必須通過繼承其中一種類型來創(chuàng)建具體結(jié)構(gòu)和聯(lián)合類型,并至少定義一個(gè)_fields_類變量。ctypes將創(chuàng)建描述符 s,允許通過直接屬性訪問來讀取和寫入字段。這些是

_fields_

定義結(jié)構(gòu)字段的序列。項(xiàng)目必須是2元組或3元組。第一項(xiàng)是字段的名稱,第二項(xiàng)指定字段的類型; 它可以是任何ctypes數(shù)據(jù)類型。

對于整數(shù)類型字段c_int,可以給出第三個(gè)可選項(xiàng)。它必須是一個(gè)小的正整數(shù),用于定義字段的位寬。

字段名稱在一個(gè)結(jié)構(gòu)或聯(lián)合中必須是唯一的。未選中此選項(xiàng),重復(fù)名稱時(shí)只能訪問一個(gè)字段。

可以在定義Structure子類的類語句之后定義_fields_類變量,這允許創(chuàng)建直接或間接引用自身的數(shù)據(jù)類型:

  1. class List(Structure):
  2. pass
  3. List._fields_ = [("pnext", POINTER(List)),
  4. ...
  5. ]

_fields_類變量但是,必須被定義在第一次使用之前的類型(創(chuàng)建一個(gè)實(shí)例,sizeof()被稱為其上,等等)。稍后對_fields_類變量的賦值將引發(fā)AttributeError。

可以定義結(jié)構(gòu)類型的子類,它們繼承基類的字段以及_fields_子子類中定義的字段(如果有的話)。

_pack_

一個(gè)可選的小整數(shù),允許覆蓋實(shí)例中結(jié)構(gòu)字段的對齊方式。 _pack_必須在_fields_分配時(shí)定義,否則它將無效。

_anonymous_

一個(gè)可選序列,列出未命名(匿名)字段的名稱。 _anonymous_必須在_fields_分配時(shí)定義,否則它將無效。

此變量中列出的字段必須是結(jié)構(gòu)或聯(lián)合類型字段。 ctypes將在結(jié)構(gòu)類型中創(chuàng)建允許直接訪問嵌套字段的描述符,而無需創(chuàng)建結(jié)構(gòu)或聯(lián)合字段。

這是一個(gè)示例類型(Windows):

  1. class _U(Union):
  2. _fields_ = [("lptdesc", POINTER(TYPEDESC)),
  3. ("lpadesc", POINTER(ARRAYDESC)),
  4. ("hreftype", HREFTYPE)]
  5. class TYPEDESC(Structure):
  6. _anonymous_ = ("u",)
  7. _fields_ = [("u", _U),
  8. ("vt", VARTYPE)]

TYPEDESC結(jié)構(gòu)描述了COM數(shù)據(jù)類型,該vt字段指定哪個(gè)聯(lián)合字段有效。由于該u字段被定義為匿名字段,因此現(xiàn)在可以直接從TYPEDESC實(shí)例訪問成員。td.lptdesc并且td.u.lptdesc 是等價(jià)的,但前者更快,因?yàn)樗恍枰獎(jiǎng)?chuàng)建臨時(shí)聯(lián)合實(shí)例:

  1. td = TYPEDESC()
  2. td.vt = VT_PTR
  3. td.lptdesc = POINTER(some_type)
  4. td.u.lptdesc = POINTER(some_type)

可以定義結(jié)構(gòu)的子類,它們繼承基類的字段。如果子類定義具有單獨(dú)的 _fields_變量,則在此指定的字段將附加到基類的字段中。

結(jié)構(gòu)和聯(lián)合構(gòu)造函數(shù)接受位置和關(guān)鍵字參數(shù)。位置參數(shù)用于按照出現(xiàn)的順序初始化成員字段_fields_。構(gòu)造函數(shù)中的關(guān)鍵字參數(shù)被解釋為屬性賦值,因此它們將_fields_使用相同的名稱進(jìn)行初始化 ,或者為不存在的名稱創(chuàng)建新屬性_fields_

   15.17.2.9。數(shù)組和指針

class ctypes.Array* args 

數(shù)組的抽象基類。

創(chuàng)建具體數(shù)組類型的推薦方法是將任何ctypes數(shù)據(jù)類型與正整數(shù)相乘 。或者,您可以繼承此類型并定義_length__type_類變量。可以使用標(biāo)準(zhǔn)下標(biāo)和切片訪問來讀取和寫入數(shù)組元素; 對于切片讀取,所得到的物體是 本身Array

_length_

一個(gè)正整數(shù),指定數(shù)組中元素的數(shù)量。超出范圍的下標(biāo)導(dǎo)致IndexError。將由返回len()。

_type_

指定數(shù)組中每個(gè)元素的類型。

數(shù)組子類構(gòu)造函數(shù)接受位置參數(shù),用于按順序初始化元素。

ctypes._Pointer

指針的私有抽象基類。

通過POINTER()使用將指向的類型調(diào)用來創(chuàng)建具體指針類型; 這是由自動(dòng)完成的 pointer()。

如果指針指向數(shù)組,則可以使用標(biāo)準(zhǔn)下標(biāo)和切片訪問來讀取和寫入其元素。指針對象沒有大小,因此len()會(huì)提高TypeError。否定下標(biāo)將在指針之前從內(nèi)存中讀?。ㄈ缭贑中),并且超出范圍的下標(biāo)可能會(huì)因訪問沖突而崩潰(如果您很幸運(yùn))。

_type_

指定指向的類型。

contents

返回指針指向的對象。分配給此屬性會(huì)將指針更改為指向指定的對象。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多