Python調用C/C++動態鏈接庫

jopen 11年前發布 | 22K 次閱讀 Python Python開發
1, 首先確定你的python支持不支持ctypes 

python2.7以后ctypes已經是標配了,2.4以后的版本得自己裝下ctypes

2,加載動態庫 

     兩種加載方式

     >>> from ctypes import *
     >>> libc = cdll . LoadLibrary ( "libc.so.6" )
     >>> libc.printf("%d",2)
     >>> from ctypes import *
     >>> libc = CDLL ( "libc.so.6" )
     >>> libc.printf("%d",2)
 

3, 調用系統函數 

   上面的例子已經調用了系統函數printf,這里再給幾個其他例子

     >>> from ctypes import *
     >>> libc = CDLL ( "libc.so.6" )
     >>> print libc . time ( None )
     1308019893
     >>> print libc.atoi("234")
     234
 

4,ctypes 數據類型和 C數據類型 對照表 
ctypes type C type Python type
c_bool _Bool bool (1)
c_char char 1-character string
c_wchar wchar_t 1-character unicode string
c_byte char int/long
c_ubyte unsigned char int/long
c_short short int/long
c_ushort unsigned short int/long
c_int int int/long
c_uint unsigned int int/long
c_long long int/long
c_ulong unsigned long int/long
c_longlong __int64 or long long int/long
c_ulonglong unsigned __int64 or unsigned long long int/long
c_float float float
c_double double float
c_longdouble long double float
c_char_p char * (NUL terminated) string or None
c_wchar_p wchar_t * (NUL terminated) unicode or None
c_void_p void * int/long or None



這些數據都可以用一個默認值進行創建

>>> c_int()
c_long(0)
>>> c_char_p("Hello, World")
c_char_p('Hello, World')
>>> c_ushort(-3)
c_ushort(65533)
>>>
 

這些數據也可以被改變:

>>> 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_char_p(s)
>>> print c_s
c_char_p('Hello, World')
>>> c_s.value = "Hi, there"
>>> print c_s
c_char_p('Hi, there')
>>> print s                 # first string is unchanged
Hello, World
>>>
 

如果需要可改變內容的字符串,需要使用 create_string_buffer()


>>> from ctypes import *
>>> p = create_string_buffer(3)      # create a 3 byte buffer, initialized to NUL bytes
>>> print sizeof(p), repr(p.raw)
3 '/x00/x00/x00'
>>> p = create_string_buffer("Hello")      # create a buffer containing a NUL terminated string
>>> print sizeof(p), repr(p.raw)
6 'Hello/x00'
>>> print repr(p.value)
'Hello'
>>> p = create_string_buffer("Hello", 10)  # create a 10 byte buffer
>>> print sizeof(p), repr(p.raw)
10 'Hello/x00/x00/x00/x00/x00'
>>> p.value = "Hi"
>>> print sizeof(p), repr(p.raw)
10 'Hi/x00lo/x00/x00/x00/x00/x00'
>>>
 

5,函數返回類型 

函數默認返回 C int 類型,如果需要返回其他類型,需要設置函數的 restype 屬性

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

6,傳遞指針或者引用 

很多情況下 C 函數需要傳遞指針或者引用,ctypes也完美的支持這一點
byref() 用來傳遞引用參數,pointer() 函數也可以完成同樣的工作,但pointer()會創建一個實際的指針對象,如果你不需要一個指針對象,
用byref()會快很多

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

7,結構體和聯合 
結構體和聯合必須從 Structure 和 Union 繼承,子類必須定義 
_fields_ 屬性,_fields_ 屬性必須是一個2元組的列表,
包括一個field名字和field的類型
field類型 必須是一個ctypes的類型例如 c_int, 或者其他繼承自ctypes的類型,結構體,聯合,數組,指針。

下面的例子演示一個 POINT結構體,包括 field  X,Y

>>> 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 ?
ValueError
: too many initializers
>>>
 

一個復雜點的例子,field類型也是一個結構體

>>> 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))
 

8,數組 

數組定義很簡單

定義一個有10個POINT元素的數組

TenPointsArrayType = POINT * 10 

初始化和使用數組:

>>> 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,
...
1 2 3 4 5 6 7 8 9 10
>>> 



9,指針 
pointer() 函數可以創建一個指針

Pointer實例有一個 contents屬性 返回指針指向的對象

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


可以改變指針指向的內容

>>> 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)
>>> 


以上都是ctypes的基本用法,對普通的開發人員來說,基本夠用了

更詳細的說明請參考:http://docs.python.org/library/ctypes.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!