考虑下面这个简单的C源代码,它计算一个由int
组成的数组的平均值,将其存储在一个 struct 中并返回错误代码:
#include <stdio.h>
enum errors {
NO_ERRORS,
EMPTY_ARRAY
};
struct Result {
double mean;
};
enum errors calculateMean(struct Result *result, int *array, int length) {
if (length == 0) {
return EMPTY_ARRAY; // Return EMPTY_ARRAY if the array is empty
}
int sum = 0;
for (int i = 0; i < length; i++) {
sum += array[i];
}
result->mean = (double)sum / length;
return NO_ERRORS; // Return NO_ERRORS if calculation is successful
}
代码被编译成一个名为libtest_ctypes.so
的共享库.
我有以下ctype接口:
import ctypes
import enum
import numpy as np
import enum
lib_path = "./libtest_ctypes.so"
lib = ctypes.CDLL(lib_path)
# The Result structure
class Result(ctypes.Structure):
_fields_ = [("mean", ctypes.c_double)]
# The Errors enum
class Errors(enum.IntEnum):
NO_ERRORS = 0
EMPTY_ARRAY = 1
# Defining a signature for `calculateMean`
calculate_mean = lib.calculateMean
calculate_mean.argtypes = [ctypes.POINTER(Result), ctypes.POINTER(ctypes.c_int), ctypes.c_int]
calculate_mean.restype = Errors
# Runs `calculateMean`
def calculate_mean_interface(array):
result = Result()
length = len(array)
c_array = array.ctypes.data_as(ctypes.POINTER(ctypes.c_int))
error = calculate_mean(ctypes.byref(result), c_array, length)
return error, result
if __name__ == "__main__":
array = np.array([1, 2, 3, 4, 5])
error, result = calculate_mean_interface(array)
if error == Errors.EMPTY_ARRAY:
print("Error: Empty array!")
elif error == Errors.NO_ERRORS:
print("Mean:", result.mean)
运行Python接口会给出错误的结果1.2
.
据我所知,这是由于我机器上的NumPy数组(64位整数)和C的int
之间的类型不同.
我可以得到正确的结果3.0
,通过NumPy的.astype()
将数组转换为ctype.c_int
:
def calculate_mean_interface(array):
result = Result()
length = len(array)
#** CAST ARRAY TO CTYPES.C_INT**
array = array.astype(ctypes.c_int)
c_array = array.ctypes.data_as(ctypes.POINTER(ctypes.c_int))
error = calculate_mean(ctypes.byref(result), c_array, length)
return error, result
然而,NumPy的选角需要额外的内存和时间. 什么是最好的方法,以达到正确的结果,而不是铸造? 我希望这是可移植的,如果可能的话,我不想在初始化NumPy数组时指定数据类型.