Python Ctypes 传递数据指针
Python Ctypes passing pointer for data
我正在访问 API,但无法返回数据。两个浮点指针将指向一个数据数组。我必须假设 API 工作正常。一个不同的函数调用提供了我正在检索的数据的长度。尝试时此值低于 length
。
函数的 C 头文件
int function(int, float * data1, float * data2)
ctypes 设置
dll.function.argtypes = (c_int, POINTER(c_float), POINTER(c_float))
dll.function.restypes = c_int
尝试 1 失败:
x = c_float()
y = c_float()
status = dll.function(1, byref(x), byref(y))
程序崩溃或访问冲突写入。
失败的尝试 2:
x = POINTER(c_float)()
y = POINTER(c_float)()
status = dll.function(1, x, y)
空指针错误
失败的尝试 3:
dll.function.argtypes = (c_int, c_void_p, c_void_p)
x = c_void_p()
y = c_void_p()
status = dll.function(1, x, y)
空指针错误
失败的尝试 4:
array = c_float * length
x = array()
y = array()
status = dll.function(1, byref(x), byref(y))
程序崩溃
第 5 次尝试失败:
array = c_float * length
x = POINTER(array)()
y = POINTER(array)()
status = dll.function(1, x, y)
空指针错误或 ArgumentError:预期 LP_c_float 实例而不是 LP_c_float_Array_[length]
第 6 次尝试失败:
x = (c_float*length)()
y = (c_float*length)()
a = cast(x, POINTER(c_float))
b = cast(y, POINTER(c_float))
status = dll.function(1, a, b)
程序崩溃
我错过了什么,为什么?
我相信参数类型是正确的。我正在尝试适当地与他们会面,但仍然存在问题。我需要以某种方式 "malloc" 内存吗? (确定拿到数据后需要free)
这是 Windows 7 和 Python 2.7 32 位。
我已查看其他类似问题,但未找到解决方案。我想知道,在这一点上,我是否可以将此问题归咎于 API。
这真的取决于你用这些浮点指针做什么。
如果你想遍历它,即
for(int i = 0; i < size; i++)
printf("%f\n%, data1[i])
那么可以肯定这是有问题的,因为没有分配数组。您只是传递了一个指向浮点数的指针。就这些了。
您需要先分配该内存。为此,尝试 4 看起来更有希望,但我怀疑您的 C 函数内部有问题导致崩溃。
如果没有看到该功能的实现,很难说。
在 [Python.Docs]: ctypes - Type conversions 中解释了指针和数组的处理。
我为你准备了一个虚拟示例。
main00.c:
#if defined(_WIN32)
# define DECLSPEC_DLLEXPORT __declspec(dllexport)
#else
# define DECLSPEC_DLLEXPORT
#endif
static int kSize = 5;
DECLSPEC_DLLEXPORT int size() {
return kSize;
}
DECLSPEC_DLLEXPORT int function(int dummy, float *data1, float *data2) {
for (int i = 0; i < kSize; i++) {
data1[i] = dummy * i;
data2[i] = -dummy * (i + 1);
}
return 0;
}
code00.py:
#!/usr/bin/env python
import sys
import ctypes as ct
c_float_p = ct.POINTER(ct.c_float)
def main(*argv):
dll = ct.CDLL("./dll00.so")
size = dll.size
size.argtypes = []
size.restype = ct.c_int
function = dll.function
function.argtypes = [ct.c_int, c_float_p, c_float_p]
function.restype = ct.c_int
sz = size()
print(sz)
data1 = (ct.c_float * sz)()
data2 = (ct.c_float * sz)()
res = function(1, ct.cast(data1, c_float_p), ct.cast(data2, c_float_p))
for i in range(sz):
print(data1[i], data2[i])
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
备注:
- C 部分试图模仿您的 .dll 所做的(或者至少是我所理解的):
- size - 获取数组大小
- function - 填充数组(直到它们的大小 - 假设它们由调用者正确分配)
- Python 部分很简单:
- 加载 .dll
- 定义argtypes和restype(在你的代码中是restype's) 对于 2 个函数(对于 size_func 没有必要)
- 获取长度
- 初始化数组
- 使用ctypes.cast
将它们传递给function_func
Output(在 Lnx 上,因为构建 C 代码要简单得多,但是也适用于 Win):
[cfati@cfati-ubtu16x64-0:~/Work/Dev/Whosebug/q050043861]> gcc -shared -o dll00.so main00.c
[cfati@cfati-ubtu16x64-0:~/Work/Dev/Whosebug/q050043861]> python3 code00.py
Python 3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0] 64bit on linux
5
0.0 -1.0
1.0 -2.0
2.0 -3.0
3.0 -4.0
4.0 -5.0
我正在访问 API,但无法返回数据。两个浮点指针将指向一个数据数组。我必须假设 API 工作正常。一个不同的函数调用提供了我正在检索的数据的长度。尝试时此值低于 length
。
函数的 C 头文件
int function(int, float * data1, float * data2)
ctypes 设置
dll.function.argtypes = (c_int, POINTER(c_float), POINTER(c_float))
dll.function.restypes = c_int
尝试 1 失败:
x = c_float()
y = c_float()
status = dll.function(1, byref(x), byref(y))
程序崩溃或访问冲突写入。
失败的尝试 2:
x = POINTER(c_float)()
y = POINTER(c_float)()
status = dll.function(1, x, y)
空指针错误
失败的尝试 3:
dll.function.argtypes = (c_int, c_void_p, c_void_p)
x = c_void_p()
y = c_void_p()
status = dll.function(1, x, y)
空指针错误
失败的尝试 4:
array = c_float * length
x = array()
y = array()
status = dll.function(1, byref(x), byref(y))
程序崩溃
第 5 次尝试失败:
array = c_float * length
x = POINTER(array)()
y = POINTER(array)()
status = dll.function(1, x, y)
空指针错误或 ArgumentError:预期 LP_c_float 实例而不是 LP_c_float_Array_[length]
第 6 次尝试失败:
x = (c_float*length)()
y = (c_float*length)()
a = cast(x, POINTER(c_float))
b = cast(y, POINTER(c_float))
status = dll.function(1, a, b)
程序崩溃
我错过了什么,为什么?
我相信参数类型是正确的。我正在尝试适当地与他们会面,但仍然存在问题。我需要以某种方式 "malloc" 内存吗? (确定拿到数据后需要free)
这是 Windows 7 和 Python 2.7 32 位。
我已查看其他类似问题,但未找到解决方案。我想知道,在这一点上,我是否可以将此问题归咎于 API。
这真的取决于你用这些浮点指针做什么。
如果你想遍历它,即
for(int i = 0; i < size; i++)
printf("%f\n%, data1[i])
那么可以肯定这是有问题的,因为没有分配数组。您只是传递了一个指向浮点数的指针。就这些了。
您需要先分配该内存。为此,尝试 4 看起来更有希望,但我怀疑您的 C 函数内部有问题导致崩溃。
如果没有看到该功能的实现,很难说。
在 [Python.Docs]: ctypes - Type conversions 中解释了指针和数组的处理。
我为你准备了一个虚拟示例。
main00.c:
#if defined(_WIN32)
# define DECLSPEC_DLLEXPORT __declspec(dllexport)
#else
# define DECLSPEC_DLLEXPORT
#endif
static int kSize = 5;
DECLSPEC_DLLEXPORT int size() {
return kSize;
}
DECLSPEC_DLLEXPORT int function(int dummy, float *data1, float *data2) {
for (int i = 0; i < kSize; i++) {
data1[i] = dummy * i;
data2[i] = -dummy * (i + 1);
}
return 0;
}
code00.py:
#!/usr/bin/env python
import sys
import ctypes as ct
c_float_p = ct.POINTER(ct.c_float)
def main(*argv):
dll = ct.CDLL("./dll00.so")
size = dll.size
size.argtypes = []
size.restype = ct.c_int
function = dll.function
function.argtypes = [ct.c_int, c_float_p, c_float_p]
function.restype = ct.c_int
sz = size()
print(sz)
data1 = (ct.c_float * sz)()
data2 = (ct.c_float * sz)()
res = function(1, ct.cast(data1, c_float_p), ct.cast(data2, c_float_p))
for i in range(sz):
print(data1[i], data2[i])
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
备注:
- C 部分试图模仿您的 .dll 所做的(或者至少是我所理解的):
- size - 获取数组大小
- function - 填充数组(直到它们的大小 - 假设它们由调用者正确分配)
- Python 部分很简单:
- 加载 .dll
- 定义argtypes和restype(在你的代码中是restype's) 对于 2 个函数(对于 size_func 没有必要)
- 获取长度
- 初始化数组
- 使用ctypes.cast 将它们传递给function_func
Output(在 Lnx 上,因为构建 C 代码要简单得多,但是也适用于 Win):
[cfati@cfati-ubtu16x64-0:~/Work/Dev/Whosebug/q050043861]> gcc -shared -o dll00.so main00.c [cfati@cfati-ubtu16x64-0:~/Work/Dev/Whosebug/q050043861]> python3 code00.py Python 3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0] 64bit on linux 5 0.0 -1.0 1.0 -2.0 2.0 -3.0 3.0 -4.0 4.0 -5.0