使用ctypes訪問C代碼

阿裏雲問答 2022-01-07 21:13:14 阅读数:650

使用 ctypes

你有一些C函數已經被編譯到共享庫或DLL中。你希望可以使用純Python代碼調用這些函數, 而不用編寫額外的C代碼或使用第三方擴展工具。




采納答案1:

可以參考這篇文章: https://www.baidu.com/link?url=6djl4oF9q-bjXsKIc7n5xA5eoO3YbD_ISURCaytWx9o0B2dmmEhXclgxb_R




采納答案2:
對於需要調用C代碼的一些小的問題,通常使用Python標准庫中的 ctypes 模塊就足够了。 要使用 ctypes ,你首先要確保你要訪問的C代碼已經被編譯到和Python解釋器兼容 (同樣的架構、字大小、編譯器等)的某個共享庫中了。 為了進行本節的演示,假設你有一個共享庫名字叫 libsample.so ,裏面的內容就是15章介紹部分那樣。 另外還假設這個 libsample.so 文件被放置到比特於 sample.py 文件相同的目錄中了。要訪問這個函數庫,你要先構建一個包裝它的Python模塊,如下這樣:# sample.pyimport ctypesimport os# Try to locate the .so file in the same directory as this file_file = 'libsample.so'_path = os.path.join(*(os.path.split(__file__)[:-1] + (_file,)))_mod = ctypes.cdll.LoadLibrary(_path)# int gcd(int, int)gcd = _mod.gcdgcd.argtypes = (ctypes.c_int, ctypes.c_int)gcd.restype = ctypes.c_int# int in_mandel(double, double, int)in_mandel = _mod.in_mandelin_mandel.argtypes = (ctypes.c_double, ctypes.c_double, ctypes.c_int)in_mandel.restype = ctypes.c_int# int divide(int, int, int *)_divide = _mod.divide_divide.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))_divide.restype = ctypes.c_intdef divide(x, y): rem = ctypes.c_int() quot = _divide(x, y, rem) return quot,rem.value# void avg(double *, int n)# Define a special type for the 'double *' argumentclass DoubleArrayType: def from_param(self, param): typename = type(param).__name__ if hasattr(self, 'from_' + typename): return getattr(self, 'from_' + typename)(param) elif isinstance(param, ctypes.Array): return param else: raise TypeError("Can't convert %s" % typename) # Cast from array.array objects def from_array(self, param): if param.typecode != 'd': raise TypeError('must be an array of doubles') ptr, _ = param.buffer_info() return ctypes.cast(ptr, ctypes.POINTER(ctypes.c_double)) # Cast from lists/tuples def from_list(self, param): val = ((ctypes.c_double)*len(param))(*param) return val from_tuple = from_list # Cast from a numpy array def from_ndarray(self, param): return param.ctypes.data_as(ctypes.POINTER(ctypes.c_double))DoubleArray = DoubleArrayType()_avg = _mod.avg_avg.argtypes = (DoubleArray, ctypes.c_int)_avg.restype = ctypes.c_doubledef avg(values): return _avg(values, len(values))# struct Point { }class Point(ctypes.Structure): _fields_ = [('x', ctypes.c_double), ('y', ctypes.c_double)]# double distance(Point *, Point *)distance = _mod.distancedistance.argtypes = (ctypes.POINTER(Point), ctypes.POINTER(Point))distance.restype = ctypes.c_double如果一切正常,你就可以加載並使用裏面定義的C函數了。例如:>>> import sample>>> sample.gcd(35,42)7>>> sample.in_mandel(0,0,500)1>>> sample.in_mandel(2.0,1.0,500)0>>> sample.divide(42,8)(5, 2)>>> sample.avg([1,2,3])2.0>>> p1 = sample.Point(1,2)>>> p2 = sample.Point(4,5)>>> sample.distance(p1,p2)4.242640687119285>>>

版权声明:本文为[阿裏雲問答]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201072113136358.html