如果 numpy 数组未进行强制转换,通过 ctypes 将 numpy 数组传递给 C 函数会给出错误的结果

问题描述 投票:0回答:1

考虑这个简单的 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。

python c ctypes
1个回答
0
投票

你可以试试这个:

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
© www.soinside.com 2019 - 2024. All rights reserved.