我用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。我是否犯了一个明显的错误,导致该函数计算错误?
答案 0 :(得分:2)
列出[Python 3.Docs]: ctypes - A foreign function library for Python。
为了在调用函数(驻留在 .dll 中时,将所有内容正确转换( Python <=> C )( .so )),需要指定2件事(不包括 x86 调用约定( Win )):
在 CTypes 中,这可以通过指定:
argtypes
-包含每个参数( CTypes )类型的列表(按它们在函数头中的显示顺序)restype
-单个 CTypes 类型
其中的任何一个(必要时为 1 )将导致应用默认设置:所有内容均已处理( C89 样式)为 int ,(在大多数系统上) 32 位长。
这会生成未定义行为 (2) (当错误指定错误代码时也适用)。
您拼错了 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]: Undefined behavior)是一种情况,其中一段代码的结果无法“预测”(或保证)。主要情况:
它的优点在于,有时似乎是完全随机的,有时在某些特定情况下(仅在不同的机器,不同的 OS es,不同的环境……),它只能“复制”。最重要的是,所有这些纯属巧合!问题出在代码上(可能是当前代码(最高机率)或它使用的其他代码(库,编译器)。