考虑这个简单的 C 源代码,它计算
int
数组的平均值,将其存储在结构中并返回错误代码:
#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
的共享库中。
我有以下 ctypes 接口:
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的ctype.c_int
将数组转换为.astype()
:
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 数组时指定 dtype。
你可以试试这个:
def calculate_mean_interface(array):
result = Result()
length = len(array)
# Check if casting is necessary
if array.dtype != np.int32:
array = array.astype('int32', casting='safe', copy=False)
c_array = array.ctypes.data_as(ctypes.POINTER(ctypes.c_int))
error = calculate_mean(ctypes.byref(result), c_array, length)
return error, result