一、ctypes
标准库的一个模块。
ctypes是最流行的模块,用于动态或共享库的函数调用,而不需要编写自定义C扩展。
在ctypes中有4种类型的动态库加载器和两个使用它们的约定。表示动态和共享库的类是:
1.1 ctypes.CDLL
1.2 ctypes.PyDLL
1.3 ctypes.OleDLL和ctypes.WinDLL。
ctypes.OleDLL和ctypes.WinDLL仅在Windows上可用,关于加载dll动态库,请参考:https//docs.python.org/3.6/ctypes.html
import ctypes
from ctypes.util import find_library
#加载libc.so动态库
libc = ctypes.cdll.LoadLibrary(find_library('c'))
if __name__ == "__main__":
libc.printf(b"Hello world!\n")
ctypes类型、C类型与Python类型
类型对应表:
ctypes type | C type | Python type |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 1-character bytes object |
c_wchar | wchar_t | 1-character string |
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 or long long | int |
c_ulonglong | unsigned __int64 or unsigned long long | int |
c_size_t | size_t | int |
c_ssize_t | ssize_t or Py_ssize_t | int |
c_float | float | float |
c_double | double | float |
c_longdouble | long double | float |
c_char_p | char * (NUL terminated) | bytes object or None |
c_wchar_p | wchar_t * (NUL terminated) | string or None |
c_void_p | void * | int or None |
注意:
1. 上面类型还有别名,比如c_byte
的别名就是class ctypes.c_uint8
,别名体现了位数。
2. 上面所有类型都继承class ctypes._SimpleCData
,该类只有唯一的属性value
。
二、cffi
CFFI是Python的一个外部函数接口,是ctypes的一个替代品。它不是标准库的一部分。
# -*- coding: utf-8 -*-
from random import shuffle
from cffi import FFI
ffi = FFI()
ffi.cdef("""
void qsort(void *base, size_t nel, size_t width,
int (*compar)(const void *, const void *));
""")
C = ffi.dlopen(None)
@ffi.callback("int(void*, void*)")
def cffi_int_compare(a, b):
# Callback signature requires exact matching of types.
# this involves less more maginc than in ctypes
# but also makes you more specific and requires
# explicit casting
int_a = ffi.cast('int*', a)[0]
int_b = ffi.cast('int*', b)[0]
print(" %s cmp %s" % (int_a, int_b))
# according to qsort specification this should return:
# * less than zero if a < b
# * zero if a == b
# * more than zero if a > b
return int_a - int_b
def main():
numbers = list(range(5))
shuffle(numbers)
print("shuffled: ", numbers)
c_array = ffi.new("int[]", numbers)
C.qsort(
# pointer to the sorted array
c_array,
# length of the array
len(c_array),
# size of single array element
ffi.sizeof('int'),
# callback (pointer to the C comparison function)
cffi_int_compare,
)
print("sorted: ", list(c_array))
if __name__ == "__main__":
main()