我用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。我是否犯了一个明显的错误,导致该函数计算错误?

评论

argtypes(以s结尾)。 python docs

#1 楼

清单[Python 3.Docs]:ctypes-Python的外部函数库。
为了在调用函数(驻留在.dll(.so)中)时正确转换所有内容(Python <=> C) ),需要指定2项内容(不考虑x86调用约定(Win)):

参数类型
返回类型

在CTypes中,这是通过以下方式实现的:指定:


argtypes-包含每个参数(CType)类型的列表(实际上是序列)(按它们在函数头中的出现顺序)

restype -单个CTypes类型

旁注:上述的替代方法,是对外部函数(CFUNCTYPE,WINFUNCTYPE,PYFUNCTYPE)进行原型设计-请检查“函数原型”部分(在开头的URL中)。
无论如何:

未指定

拼写错误(基本上与上一个项目符号相同)

其中任何一个(需要时为(1) ),将导致应用默认设置:将所有内容(C89样式)都视为ints,(在大多数系统上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
 

相同(或非常相似)场景(有很多其他场景)的某些(更具破坏性的)结果:

[SO]:Python ctypes cdll.LoadLibrary,实例化对象,执行其方法,私有变量地址被截断(@CristiFati的回答)
[SO]:Python ctypes在不同的操作系统上发布(@CristiFati的答案)


脚注


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


不带参数的函数:
   function_from_dll.argtypes = []
 



函数返回void:
   function_from_dll.restype = None
 





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

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

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



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