ctype模块可以让python 调用c写的动态库。主要是对应两种语言的基本数据类型,指针,函数指针,结构体等类型的支持,从而可以让python可调用c库。
例子1,用c自定义一个函数,编译后用python调用:
great_module.c
C
// great_module.c
//#include
#ifdef _MSC_VER
#define DLL_EXPORT __declspec( dllexport )
#else
#define DLL_EXPORT
#endif
DLL_EXPORT int great_function(unsigned int n) {
//return __mm_popcnt_u32(n);
return n+1;
}
DLL_EXPORT int array_get(int a[], int index) {
return a[index];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// great_module.c
//#include
#ifdef _MSC_VER
#define DLL_EXPORT __declspec( dllexport )
#else
#define DLL_EXPORT
#endif
DLL_EXPORTintgreat_function(unsignedintn){
//return __mm_popcnt_u32(n);
returnn+1;
}
DLL_EXPORTintarray_get(inta[],intindex){
returna[index];
}
编译后生成动态库文件:
linux:
Shell
gcc -fPIC -shared great_module.c -o great_module.so
1
gcc-fPIC-sharedgreat_module.c-ogreat_module.so
windows:
Shell
gcc -fPIC -shared great_module.c -o great_module.dll
1
gcc-fPIC-sharedgreat_module.c-ogreat_module.dll
python 调用动态库:
great_module_test.py
Python
from ctypes import *
# igreat_module = cdll.LoadLibrary('./great_module.dll')
great_module = cdll.LoadLibrary('./great_module.so')
print great_module.great_function(15)
type_int_array_10 = c_int * 10 # generate ctypes array of basic type
my_array = type_int_array_10() # instantiate a object using new array type
my_array[2] = c_int(5)
print great_module.array_get(my_array,2) #5
print great_module.array_get(my_array,1) #0
print great_module.array_get(my_array,0) #0
1
2
3
4
5
6
7
8
9
10
11
fromctypesimport*
# igreat_module = cdll.LoadLibrary('./great_module.dll')
great_module=cdll.LoadLibrary('./great_module.so')
printgreat_module.great_function(15)
type_int_array_10=c_int*10# generate ctypes array of basic type
my_array=type_int_array_10()# instantiate a object using new array type
my_array[2]=c_int(5)
printgreat_module.array_get(my_array,2)#5
printgreat_module.array_get(my_array,1)#0
printgreat_module.array_get(my_array,0)#0
运行结果:
Shell
pi@raspberrypi:~/python-ctypes $ python great_module_test.py
16
5
0
0
1
2
3
4
5
pi@raspberrypi:~/python-ctypes$pythongreat_module_test.py
16
5
0
0
例子2, 调用系统的printf函数, 跨平台支持mac, linux, windows:
printf.py
Python
from ctypes import *
from platform import *
print system()
cdll_names = {
'Darwin' : 'libc.dylib',
'Linux' : 'libc.so.6',
'Windows': 'msvcrt.dll'
}
clib = cdll.LoadLibrary(cdll_names[system()])
clib.printf(c_char_p("Hello %d %f\n"), c_int(15), c_double(2.3))
str_format = c_char_p()
int_val = c_int()
double_val = c_double()
str_format.value = "Hello %d %f\n"
int_val.value = 15
double_val.value = 2.3
clib.printf(str_format, int_val, double_val)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fromctypesimport*
fromplatformimport*
printsystem()
cdll_names={
'Darwin':'libc.dylib',
'Linux':'libc.so.6',
'Windows':'msvcrt.dll'
}
clib=cdll.LoadLibrary(cdll_names[system()])
clib.printf(c_char_p("Hello %d %f\n"),c_int(15),c_double(2.3))
str_format=c_char_p()
int_val=c_int()
double_val=c_double()
str_format.value="Hello %d %f\n"
int_val.value=15
double_val.value=2.3
clib.printf(str_format,int_val,double_val)
运行结果:
Shell
pi@raspberrypi:~/python-ctypes $ python printf.py
Linux
Hello 15 0.000000
Hello 15 0.000000
1
2
3
4
pi@raspberrypi:~/python-ctypes$pythonprintf.py
Linux
Hello150.000000
Hello150.000000
例子3,关于类型自动转换:
可以自动转换:
001_type_auto_conv_Pass.py
Python
from ctypes import *
from platform import *
cdll_names = {
'Darwin' : 'libc.dylib',
'Linux' : 'libc.so.6',
'Windows': 'msvcrt.dll'
}
clib = cdll.LoadLibrary(cdll_names[system()])
# can auto convert type
s1 = c_char_p('a')
s3 = clib.strcat(s1, 'b')
print s1.value #ab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fromctypesimport*
fromplatformimport*
cdll_names={
'Darwin':'libc.dylib',
'Linux':'libc.so.6',
'Windows':'msvcrt.dll'
}
clib=cdll.LoadLibrary(cdll_names[system()])
# can auto convert type
s1=c_char_p('a')
s3=clib.strcat(s1,'b')
prints1.value#ab
运行结果:
能自动转换
Shell
pi@raspberrypi:~/python-ctypes $ python 001_type_auto_conv_Pass.py
ab
1
2
pi@raspberrypi:~/python-ctypes$python001_type_auto_conv_Pass.py
ab
001_type_auto_conv_Fail.py
Python
from ctypes import *
from platform import *
cdll_names = {
'Darwin' : 'libc.dylib',
'Linux' : 'libc.so.6',
'Windows': 'msvcrt.dll'
}
clib = cdll.LoadLibrary(cdll_names[system()])
# can Not auto convert type
clib.printf(c_char_p("Hello %d %f"), 15, 2.3)
1
2
3
4
5
6
7
8
9
10
11
12
13
fromctypesimport*
fromplatformimport*
cdll_names={
'Darwin':'libc.dylib',
'Linux':'libc.so.6',
'Windows':'msvcrt.dll'
}
clib=cdll.LoadLibrary(cdll_names[system()])
# can Not auto convert type
clib.printf(c_char_p("Hello %d %f"),15,2.3)
结果:
不能自动转换,报错
Shell
pi@raspberrypi:~/python-ctypes $ python 001_type_auto_conv_Fail.py
Traceback (most recent call last):
File "001_type_auto_conv_Fail.py", line 13, in
clib.printf(c_char_p("Hello %d %f"), 15, 2.3)
ctypes.ArgumentError: argument 3: : Don't know how to convert parameter 3
1
2
3
4
5
pi@raspberrypi:~/python-ctypes$python001_type_auto_conv_Fail.py
Traceback(mostrecentcalllast):
File"001_type_auto_conv_Fail.py",line13,in
clib.printf(c_char_p("Hello %d %f"),15,2.3)
ctypes.ArgumentError:argument3::Don'tknowhowtoconvertparameter3
例子4, 函数的参数可以是指针类型,然后可以通过参数返回值:
002_pointer_return_value.py
Python
from ctypes import *
from platform import *
cdll_names = {
'Darwin' : 'libc.dylib',
'Linux' : 'libc.so.6',
'Windows': 'msvcrt.dll'
}
clib = cdll.LoadLibrary(cdll_names[system()])
s1 = c_char_p('a')
s2 = c_char_p('b')
s3 = clib.strcat(s1,s2)
print s1.value #ab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fromctypesimport*
fromplatformimport*
cdll_names={
'Darwin':'libc.dylib',
'Linux':'libc.so.6',
'Windows':'msvcrt.dll'
}
clib=cdll.LoadLibrary(cdll_names[system()])
s1=c_char_p('a')
s2=c_char_p('b')
s3=clib.strcat(s1,s2)
prints1.value#ab
运行结果:
Shell
pi@raspberrypi:~/python-ctypes $ python 002_pointer_return_value.py
ab
1
2
pi@raspberrypi:~/python-ctypes$python002_pointer_return_value.py
ab
例子5, 指定返回值类型:
Python
from ctypes import *
from platform import *
cdll_names = {
'Darwin' : 'libc.dylib',
'Linux' : 'libc.so.6',
'Windows' : 'msvcrt.dll'
}
clib = cdll.LoadLibrary(cdll_names[system()])
s3 = clib.strcat('a', 'b')
print s3 # return a number, not 'ab'
clib.strcat.restype = c_char_p
s4 = clib.strcat('c', 'd')
print s4 # cd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fromctypesimport*
fromplatformimport*
cdll_names={
'Darwin':'libc.dylib',
'Linux':'libc.so.6',
'Windows':'msvcrt.dll'
}
clib=cdll.LoadLibrary(cdll_names[system()])
s3=clib.strcat('a','b')
prints3# return a number, not 'ab'
clib.strcat.restype=c_char_p
s4=clib.strcat('c','d')
prints4# cd
运行结果:
Shell
pi@raspberrypi:~/python-ctypes $ python 003_return_type_specify.py
1992801740
cd
1
2
3
pi@raspberrypi:~/python-ctypes$python003_return_type_specify.py
1992801740
cd
例子6, 关于多维数组,ctype 重载了 * 号
重载*号,用于生成多维数组类型
Python
from ctypes import *
type_int_array_10 = c_int * 10
type_int_array_10_10 = type_int_array_10 * 10
my_array = type_int_array_10_10()
my_array[1][2] = 3
1
2
3
4
5
6
fromctypesimport*
type_int_array_10=c_int*10
type_int_array_10_10=type_int_array_10*10
my_array=type_int_array_10_10()
my_array[1][2]=3
例子7, 指针, 用POINTER(),pointer()
用POINTER(), pointer()
Python
from ctypes import *
type_p_int = POINTER(c_int)
v = c_int(4)
p_int = type_p_int(v)
print type(p_int)
print p_int[0]
print p_int.contents
print p_int[100], "\n"
# ------above and below result are the same------
p_int = pointer(v)
print type(p_int)
print p_int[0]
print p_int.contents
print p_int[100], "\n"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fromctypesimport*
type_p_int=POINTER(c_int)
v=c_int(4)
p_int=type_p_int(v)
printtype(p_int)
printp_int[0]
printp_int.contents
printp_int[100],"\n"
# ------above and below result are the same------
p_int=pointer(v)
printtype(p_int)
printp_int[0]
printp_int.contents
printp_int[100],"\n"
运行结果:
Shell
pi@raspberrypi:~/python-ctypes $ python 005_POINTER_type.py
4
c_long(4)
1992517056
4
c_long(4)
1992517056
1
2
3
4
5
6
7
8
9
10
pi@raspberrypi:~/python-ctypes$python005_POINTER_type.py
4
c_long(4)
1992517056
4
c_long(4)
1992517056
例子8,关于函数指针,用CFUNCTYPE()
Python
from ctypes import *
from platform import *
cdll_names = {
'Darwind' : 'libc.dylib',
'Linux' : 'libc.so.6',
'Windows' : 'msvcrt.dll'
}
clib = cdll.LoadLibrary(cdll_names[system()])
CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
def py_cmp_func(a, b):
print type(a)
print "py_cmp_func", a[0], b[0]
return a[0] - b[0]
type_array_5 = c_int * 5
ia = type_array_5(5, 1, 7, 33, 99)
clib.qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fromctypesimport*
fromplatformimport*
cdll_names={
'Darwind':'libc.dylib',
'Linux':'libc.so.6',
'Windows':'msvcrt.dll'
}
clib=cdll.LoadLibrary(cdll_names[system()])
CMPFUNC=CFUNCTYPE(c_int,POINTER(c_int),POINTER(c_int))
defpy_cmp_func(a,b):
printtype(a)
print"py_cmp_func",a[0],b[0]
returna[0]-b[0]
type_array_5=c_int*5
ia=type_array_5(5,1,7,33,99)
clib.qsort(ia,len(ia),sizeof(c_int),CMPFUNC(py_cmp_func))
运行结果, linux和windows的结果有点不一样:
linux
Shell
pi@raspberrypi:~/python-ctypes $ python 006_pointer_function.py
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
1
2
3
4
5
6
7
8
9
10
11
pi@raspberrypi:~/python-ctypes$python006_pointer_function.py
py_cmp_func51
py_cmp_func3399
py_cmp_func733
py_cmp_func17
py_cmp_func57
windows
Shell
c:\python-ctypes>python 006_pointer_function.py
py_cmp_func 1 5
py_cmp_func 7 5
py_cmp_func 33 7
py_cmp_func 99 33
py_cmp_func 1 5
py_cmp_func 7 5
py_cmp_func 33 7
py_cmp_func 1 5
py_cmp_func 7 5
py_cmp_func 1 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
c:\python-ctypes>python006_pointer_function.py
py_cmp_func15
py_cmp_func75
py_cmp_func337
py_cmp_func9933
py_cmp_func15
py_cmp_func75
py_cmp_func337
py_cmp_func15
py_cmp_func75
py_cmp_func15
还参考了:
官方DOC:
dir(ctypes), 手动分了行,好看些:
Shell
pi@raspberrypi:~/python-ctypes $ python
Python 2.7.9 (default, Sep 17 2016, 20:26:04)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> dir(ctypes)
['ARRAY',
'ArgumentError',
'Array',
'BigEndianStructure',
'CDLL',
'CFUNCTYPE',
'DEFAULT_MODE',
'LibraryLoader',
'LittleEndianStructure',
'POINTER',
'PYFUNCTYPE',
'PyDLL',
'RTLD_GLOBAL',
'RTLD_LOCAL',
'SetPointerType',
'Structure',
'Union',
'_CFuncPtr',
'_FUNCFLAG_CDECL',
'_FUNCFLAG_PYTHONAPI',
'_FUNCFLAG_USE_ERRNO',
'_FUNCFLAG_USE_LASTERROR',
'_Pointer',
'_SimpleCData',
'__builtins__',
'__doc__',
'__file__',
'__name__',
'__package__',
'__path__',
'__version__',
'_c_functype_cache',
'_calcsize',
'_cast',
'_cast_addr',
'_check_size',
'_ctypes_version',
'_dlopen',
'_endian',
'_memmove_addr',
'_memset_addr',
'_os',
'_pointer_type_cache',
'_reset_cache',
'_string_at',
'_string_at_addr',
'_sys',
'_wstring_at',
'_wstring_at_addr',
'addressof',
'alignment',
'byref',
'c_bool',
'c_buffer',
'c_byte',
'c_char',
'c_char_p',
'c_double',
'c_float',
'c_int',
'c_int16',
'c_int32',
'c_int64',
'c_int8',
'c_long',
'c_longdouble',
'c_longlong',
'c_short',
'c_size_t',
'c_ssize_t',
'c_ubyte',
'c_uint',
'c_uint16',
'c_uint32',
'c_uint64',
'c_uint8',
'c_ulong',
'c_ulonglong',
'c_ushort',
'c_void_p',
'c_voidp',
'c_wchar',
'c_wchar_p',
'cast',
'cdll',
'create_string_buffer',
'create_unicode_buffer',
'get_errno',
'memmove',
'memset',
'pointer',
'py_object',
'pydll',
'pythonapi',
'resize',
'set_conversion_mode',
'set_errno',
'sizeof',
'string_at',
'wstring_at']
>>>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
pi@raspberrypi:~/python-ctypes$python
Python2.7.9(default,Sep172016,20:26:04)
[GCC4.9.2]onlinux2
Type"help","copyright","credits"or"license"formoreinformation.
>>>importctypes
>>>dir(ctypes)
['ARRAY',
'ArgumentError',
'Array',
'BigEndianStructure',
'CDLL',
'CFUNCTYPE',
'DEFAULT_MODE',
'LibraryLoader',
'LittleEndianStructure',
'POINTER',
'PYFUNCTYPE',
'PyDLL',
'RTLD_GLOBAL',
'RTLD_LOCAL',
'SetPointerType',
'Structure',
'Union',
'_CFuncPtr',
'_FUNCFLAG_CDECL',
'_FUNCFLAG_PYTHONAPI',
'_FUNCFLAG_USE_ERRNO',
'_FUNCFLAG_USE_LASTERROR',
'_Pointer',
'_SimpleCData',
'__builtins__',
'__doc__',
'__file__',
'__name__',
'__package__',
'__path__',
'__version__',
'_c_functype_cache',
'_calcsize',
'_cast',
'_cast_addr',
'_check_size',
'_ctypes_version',
'_dlopen',
'_endian',
'_memmove_addr',
'_memset_addr',
'_os',
'_pointer_type_cache',
'_reset_cache',
'_string_at',
'_string_at_addr',
'_sys',
'_wstring_at',
'_wstring_at_addr',
'addressof',
'alignment',
'byref',
'c_bool',
'c_buffer',
'c_byte',
'c_char',
'c_char_p',
'c_double',
'c_float',
'c_int',
'c_int16',
'c_int32',
'c_int64',
'c_int8',
'c_long',
'c_longdouble',
'c_longlong',
'c_short',
'c_size_t',
'c_ssize_t',
'c_ubyte',
'c_uint',
'c_uint16',
'c_uint32',
'c_uint64',
'c_uint8',
'c_ulong',
'c_ulonglong',
'c_ushort',
'c_void_p',
'c_voidp',
'c_wchar',
'c_wchar_p',
'cast',
'cdll',
'create_string_buffer',
'create_unicode_buffer',
'get_errno',
'memmove',
'memset',
'pointer',
'py_object',
'pydll',
'pythonapi',
'resize',
'set_conversion_mode',
'set_errno',
'sizeof',
'string_at',
'wstring_at']
>>>
打赏
微信扫一扫,打赏作者吧~
Post Views:
2,760