将numpy.array传递给ctypes但得到错误结果的问题

时间:2014-02-14 20:12:39

标签: python c numpy ctypes

注意:这不是一个问题 - 我解决了问题并在此处发布,试图分享我学到的东西。

我昨晚在使用numpy时遇到了问题,这就是我将它简化为短代码的方法。起初它看起来像是一个bug,但就在我尝试写这个问题时,我意识到这是我自己的错误。希望后来也有人能够从中受益于此问题!

使用WinSDK 7.1的C编译器在Win 7 x64上可以重复。 Python版本是3.3.3,使用MSC v.1600构建。 Numpy版本是1.8.0。

0)简要总结:当我将一个ndarray传递给我用c代码编译的dll时,c代码看到的数组与我传入的数组不同。

1)写一个c代码:

// testdll.c
#include <stdlib.h>

__declspec(dllexport) void copy_ndarray(double *array1, double *array2, size_t array_length);

void copy_ndarray(double *array1, double *array2, size_t array_length)
{
    size_t i;
    for(i=0; i<array_length; i++)
        array2[i] = array1[i];
    return;
}

2)编写一个python代码:

import numpy as np
import ctypes


# wrap the function from dll to python
lib = ctypes.cdll.LoadLibrary('./testdll.dll')
fun = lib.copy_ndarray
fun.restype = None
fun.argtypes = [np.ctypeslib.ndpointer(ctypes.c_double), np.ctypeslib.ndpointer(ctypes.c_double), ctypes.c_size_t]
# Initialize array1 and array2
array_length= 10
temp = np.c_[100.*np.ones(array_length), 200.*np.ones(array_length)]
array1 = temp[:, 1]
array2 = np.zeros(array_length)
fun(array1, array2, array_length)

3)运行代码。看看array1和array2是如何不同的。

1 个答案:

答案 0 :(得分:3)

当然应该是不同的!

当我使用array1 = temp[:, 1]时,array1不是真正的大小(10,)ndarray。它是temp的视图,大小为(10,2)。想想它是如何存储在内存中的 - 当指针转到c中的另一个sizeof(double)时,它将遇到temp中的下一个元素,而不是array1中的下一个元素。

修复它的方法是 - 在读取数据时不要使用ndarray视图!使用此行

array1 = temp[:, 1].copy()

制作副本,而不是简单地使用视图。

正确的python代码是:

import numpy as np
import ctypes


# wrap the function from dll to python
lib = ctypes.cdll.LoadLibrary('./testdll.dll')
fun = lib.copy_ndarray
fun.restype = None
fun.argtypes = [np.ctypeslib.ndpointer(ctypes.c_double), np.ctypeslib.ndpointer(ctypes.c_double), ctypes.c_size_t]
# Initialize array1 and array2
array_length= 10
temp = np.c_[100.*np.ones(array_length), 200.*np.ones(array_length)]
array1 = temp[:, 1].copy()
array2 = np.zeros(array_length)
fun(array1, array2, array_length)

我个人认为这很棘手,因为作为一个数据分析器(说实话,我不是......我是研究员,但足够接近!),99%的时候一个视图比副本更好,因为它更快,一旦数据被读取,我们不需要原始的ndarray。

了解这一点并记住这一点很好!