在python中通过ctypes可以直接调用c的函数,非常简单易用

下面就一步一步解释用法吧,以Linux为例讲解。

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

__int64or long long

int/long

c_ulonglong

unsigned __int64or 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的基本用法,对普通的开发人员来说,基本够用了