难以从 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*lengthctypes.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 返回浮点数的主要内容,如果未能解决你的问题,请参考以下文章

如何在python中将23位浮点数从字符串转换为浮点数并返回?

打乱一个浮点数?

js 后端返回浮点数,前端用乘法或者除法处理,得到超常值

组态王使用485如何读取仪表浮点数?

返回随机数:整数浮点数

如何从 C 中的浮点数中提取有偏指数?