难以从 Ctypes 返回浮点数
Posted
技术标签:
【中文标题】难以从 Ctypes 返回浮点数【英文标题】:Difficulty returning a float from Ctypes 【发布时间】:2020-03-21 13:56:46 【问题描述】:我目前正在尝试为一些 C++ 代码编写一个简单的包装器,以便能够传入一些信号数据,对其进行 GPU 操作并将其发送回来。目前,我已经删除了所有 GPU 元素,因为我无法让 ctypes 返回整数以外的任何内容。
我应该先说我不确定这个决定的严重性,但我只是设法通过将 C++ 函数包装在 C 函数中来使 ctypes 识别 C++ 函数。随着我尝试返回浮点数的不幸事件继续发生,我意识到无论错误的来源是什么,都可以肯定地分辨出来自 C++ 的数字和来自 C 的数字之间的区别。我稍后会回到这一点。
extern "C" float* giveLotsZeroes(int length)
float* list2 = (float*)malloc(sizeof(float)*length);
for (unsigned int i = 0; i < length; i++) list2[i] = 0;
return list2;
这是我用来测试返回浮点功能的示例 C++ 函数之一,位于文件“kernal.cu”中。它通过在“chead.h”中定义的extern float* giveLotsZeroes(int length);
和__declspec(dllexport) float* giveLotsOfZeroes(int length);
传递给C(注意函数名称中间的Of 以区分它们)。最后,float* giveLotsOfZeroes(int length) return giveLotsZeroes(length);
在包含 chead.h 的 Source.c 中定义,链接器将其编译为多线程 dll 似乎没有问题。我有一个类似的迭代,它返回一个零列表作为整数,它的功能非常好,以至于我已经在 GPU 错误处理中实现了它,并且每一行 GPU 代码似乎都会导致错误,我有有理由相信错误处理实现工作正常,但我稍后会谈到一个例外。
当尝试返回长度为 128 的整数列表时,我使用 numpy 的 ctypeslib 库取得了巨大成功,
accelerator.getLastErrorCode.restype = np.ctypeslib.ndpointer(dtype=ctypes.c_int,shape=(128,))
accelerator.getLastLineExecuted.restype = np.ctypeslib.ndpointer(dtype=ctypes.c_int,shape=(128,))
这很好用,但是如果我用我的长度变量“length”替换 128 并用 ctypes.c_float 替换 ctypes.c_int,python 返回一个通常介于 1e8 和 1e10 之间的整数。有了这样奇怪的结果,我也尝试返回单个浮点数,这产生了类似的结果,尽管人们可能会认为单值函数也返回单个值,因此不那么令人震惊。有趣的是,当我使用定义 restypes 的 np.ctypeslib.ndpointer 方法时,python type
函数仍然声称结果是 numpy.ndarray
但如果你把它当作一个,它会抱怨。我尝试过将此函数的 restypes
或函数的变体定义为 ctypes.c_float*length
或 ctypes.POINTER(ctypes.c_float*length)
,但没有成功。
事实上,我创建了两个返回单个零的函数,一个从 C++ 将其返回到 C 再到 python,另一个直接从 C 执行,并让它们都将它们的零打印到控制台以确认C 没有问题,C ++ 的零也没有问题,但是当他们到达 python 时,C 的零已经变成 1(我后来发现无论 C 试图返回什么都是这种情况)和 C++ 的零已成为一致的 164。一位朋友建议将 0
的每个实例更改为 0.0f
,从而将 164 更改为标准随机大数。
我在错误处理方面遇到的唯一问题是,在一个奇异但可重复的奇怪实例中,700
设法从一个只应该假设的函数中出来能够返回从 0 到 29 的数字。不确定这可能与其他错误有什么联系,但如果有帮助,它会有所帮助。
我已将我的代码包含在以下 pastebin 中,但请注意,大部分 python 代码只是测试什么按预期工作,什么不按预期工作。
https://pastebin.com/j7gfiKA6
【问题讨论】:
【参考方案1】:你的返回值为ctypes.POINTER(ctypes.c_float)
:
>>> from ctypes import *
>>> dll = CDLL('test')
>>> dll.giveLotsZeroes.argtypes = c_int,
>>> dll.giveLotsZeroes.restype = POINTER(c_float)
>>> x = dll.giveLotsZeroes(100)
>>> x
<__main__.LP_c_float object at 0x0000022DE407F948>
>>> x[0]
0.0
>>> x[99]
0.0
你也可以通过边界检查来获取整个数组:
>>> a = cast(x,POINTER(c_float*100)).contents
>>> a
<__main__.c_float_Array_100 object at 0x0000022DE45A5CC8>
>>> a[0]
0.0
>>> a[99]
0.0
>>> a[100]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: invalid index
转换为 Python 列表:
>>> list(a)
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
【讨论】:
这对我不起作用,无论如何,所有 dll 函数都返回整数。.contents
返回错误,因为整数没有那个,使用索引返回错误,因为整数没有索引。抱歉迟到了,我从这个特别的项目中休息了一下,以赶上学校的工作。
@Clocks 看看我的cast
。您的函数需要一个长度 (int) 并返回一个 float*
。我将该返回值从 float*
的 C 等效项转换为 (*float)[100]
(指向 100 个浮点数的数组的指针)。 .contents
取消引用数组以提供浮点数组,然后您可以使用 []
对其进行索引。我不知道你为什么指的是整数......除了length
,我的回答中的一切都是浮动的。它绝对有效,因为我编译了你的函数,上面的输出直接来自实际使用。
@Clocks 您的pastebin
链接代码的一个问题是您在很多地方使用过.restypes
。那是错误的关键字。使用.restype
(不是复数)。
我在比较它什么时候起作用和什么时候不起作用,我认为最后一条评论就是它,我只是把所有东西都放在复数形式。这可能会解决我所有的问题,谢谢以上是关于难以从 Ctypes 返回浮点数的主要内容,如果未能解决你的问题,请参考以下文章