当前位置: 首页 > 面试题库 >

https://stackoverflow.com/questions/58610333/c-function-called-from-python-via-ctypes-returns-incorrect-value/58611011#58611011

卫胜
2023-03-14
问题内容

我用C语言编写了一个简单的函数,可以将给定的数字提高到给定的幂。当我在C中调用该函数时,该函数将返回正确的值,但是当我在Python中调用该函数时,它将返回一个不同的,不正确的值。

我使用以下命令创建了共享文件: $ gcc -fPIC -shared -o test.so test.c

我尝试了C函数的不同配置,其中一些返回期望值,而有些则没有。例如,当我的函数使用return x*x而不是for循环的简单正方形时,它在Python中返回了正确的值。

我希望最终能够在python中调用C函数,该函数将返回二维C数组。

#include <stdio.h>

float power(float x, int exponent)
{
    float val = x;
    for(int i=1; i<exponent; i++){
        val = val*x;
    }
    return val;
}
from ctypes import *

so_file = '/Users/.../test.so'
functions = CDLL(so_file)

functions.power.argtype = [c_float, c_int]
functions.power.restype = c_float

print(functions.power(5,3))

当我在C中调用该函数时,我获得了125.0的预期输出,但是当我在python中调用该函数时,它返回的值为0.0。

这是我第一次使用ctypes。我是否犯了一个明显的错误,导致该函数计算错误?


问题答案:

清单[Python 3.Docs]:ctypes-Python的外部函数库。

为了在调用函数(驻留在.dll(.so)中)时正确转换所有内容(Python <=> C),需要指定2项内容(不包括x86调用约定(Win)):

参数类型
返回类型
在CTypes中,这可以通过指定:

argtypes-包含每个参数( CTypes)类型的列表(实际上是一个序列)(按它们在函数头中出现的顺序)
restype -单ctypes的类型
旁注:上述方法的替代方法是对外部函数(CFUNCTYPE,WINFUNCTYPE,PYFUNCTYPE)进行原型设计-检查Function prototypes部分(在开头的URL中)。

无论如何:

无法指定
拼写错误(基本上与上一个项目符号相同)
它们中的任何(如果需要(1) ),将导致默认被施加:所有被处理(C89风格)作为INT s,这(在大多数系统)是32位长。
这会生成未定义行为 (2)(在错误地指定它们时也适用),尤其是在64位 CPU / OS上,在这种情况下,较大类型(例如指针)的值可能会被截断。
显示的错误可能很多,有时甚至会引起误解。

您拼写了argtype(末尾缺少s)。

改正它,你应该没事

范例:

对于由libdll00.dll(libdll00.so)导出的具有以下标头的函数func00:

double func00(uint32_t ui, float f, long long vll[8], void *pv, char *pc);

在Python的等效是:

func00 = libdll00.func00
func00.argtypes = [ctypes.c_uint32, ctypes.c_float, ctypes.c_longlong * 8, ctypes.c_void_p, ctypes.POINTER(ctypes.c_char)]
'''
It would be a lot easier (nicer, and in most cases recommended)
  the last element to be ctypes.c_char_p,
  but I chose this form to illustrate pointers in general.
'''
func00.restype = ctypes.c_double

脚注
#1:从技术上讲,在某些情况下不需要指定它们。但是即使那样,最好还是指定它们,以消除任何可能的混淆:

没有参数的函数:

  function_from_dll.argtypes = []

函数返回void:

  function_from_dll.restype = None

#2:顾名思义,未定义的行为( [Wikipedia]:未定义的行为)是无法“预测”(或保证)一段代码的结果的情况。主要情况:

  • 按预期工作
  • 不能按预期工作

    • 有一些有趣的输出/副作用
    • 崩溃

它的“美”在于有时似乎是完全随机的,有时它仅在某些特定情况(不同的机器,不同的OS,不同的环境……)下“复制” 。最重要的是,所有这些纯属巧合!问题出在代码(可能是当前代码(最高机率)或它使用的其他代码(库,编译器))上。



 类似资料:
  • 问题内容: 我想了解内置函数的工作原理。令我感到困惑的是,它还可以用作装饰器,但是仅当用作内置函数时才接受参数,而不能用作装饰器。 这个例子来自文档: 的论点是,,和文档字符串。 在下面的代码中用作装饰器。它的对象是x函数,但是在上面的代码中,参数中没有对象函数的位置。 在这种情况下,x.setter和x.deleter装饰器是如何创建的? 问题答案: 该函数返回一个特殊的描述符对象: 正是这种对

  • 问题内容: 我下载了pip并运行python setup.py install,一切正常。本教程的下一步是运行,pip install 但是甚至在尝试在线查找任何内容之前,我都会收到错误消息“ bash:pip:not found”。 这是在Mac OS X上,这也是我的新手,因此我假设有些路径设置在我运行setup.py时未正确设置。我该如何进一步调查?我需要检查什么才能更好地了解问题的确切原因

  • 问题内容: 我想使用一个正则表达式来检查字符串是否仅包含大写和小写字母,数字和下划线。 问题答案: 要匹配仅包含这些字符的字符串(或空字符串),请尝试 这适用于.NET正则表达式,也可能适用于许多其他语言。 分解: 如果您不想允许使用空字符串,请使用+代替*。 正如其他人指出的那样,某些正则表达式语言具有的简写形式[a-zA-Z0-9_]。在.NET正则表达式语言中,您可以打开ECMAScript

  • 问题内容: 我将项目更新为Struts2 2.3.20版。现在,我的JSP中使用静态方法访问的所有情况都不起作用。 即。 我已经在我的struts.properties中设置了-> 并在struts.xml->中尝试过 没有成功。有谁知道发生了什么变化,我需要怎么做才能再次启用它们? 问题答案: 更新资料 卢卡斯·莱纳特(Lukasz Lenart)评论: 需要明确的是,在2.3.20的上下文中,

  • 问题内容: 我已经使用PuTTYgen生成了密钥对,并使用Pageant进行了登录,因此在系统启动时,我只需输入一次密码。 如何在Linux中实现呢?我听说过,但听说它使用了不同的密钥对格式-我不想更改Windows密钥,如果我可以在Windows和Linux中以相同的方式无缝连接,那就太好了。 问题答案: puttygen支持将您的私钥导出为OpenSSH兼容格式。然后,您可以使用OpenSSH

  • 问题内容: 我正在尝试使用Python 3中的Paramiko将特定文件从远程服务器发送到我的本地计算机。 背景:目标计算机198.18.2.2上有一个目录,其中包含许多以名称开头的时间戳目录2020… 目标机器: 源机器: 到目前为止,我已经设法构造了要执行的命令,如下所示: 码: 呼叫: 问题总是给我最新的时间戳文件夹。但是,如果该文件夹中没有该文件,我想查看具有该文件的下一个最新时间戳文件夹