使用ctypes调用C函数时,参数顺序很重要

时间:2014-09-24 18:00:36

标签: python-3.x ctypes

我的C dll来源:

#include<stdio.h>

typedef struct {
    int nums[5];
    int tp;
} Sample;

float read_float(Sample s, float* arg){
    return arg[1];
} 

调用它的Python代码的来源:

from ctypes import *

class PySample(Structure):
    _fields_ = [("nums", c_int * 5),
                ("tp", c_int)]

if __name__ == "__main__":
    libp = CDLL(r"PathToMyDLL")
    rf = libp.read_float
    rf.restype = c_float
    s = PySample()
    for i in range(5):
        s.nums[i] = (11,22,33,44,55)[i]
    s.tp = 101
    print(rf(s, (c_float*3)(0.4, 0.5, 0.6)))

使用gcc -shared编译并运行Python代码后,我得到一些随机的小数字。 但是,如果我将C函数的签名更改为:

float read_float(float* arg, Sample s)

和相应的Python打印调用:

print(rf((c_float*3)(0.4, 0.5, 0.6), s))

(即在定义和函数调用中改变参数的顺序)然后我得到正确的0.5

这不是理想的行为。我在这里做错了什么以及为什么会这样?

(64位Windows和C代码的Python 3.4.1使用gcc 4.8.1(MinGw-W64)编译)

1 个答案:

答案 0 :(得分:2)

如果添加argtypes声明,则在32位编译并与32位Python一起使用时,您的示例正常工作:

rf.argtypes = [PySample, POINTER(c_float)]

但是在64位Python中,如果失败了。我发现更改argtypes以使用指向结构的指针使其工作,即使C按值传递结构。

rf.argtypes = [POINTER(PySample), POINTER(c_float)]

但是,如果我改变你的功能来修改结构,它也会在Python中修改它。从C调用函数并实际传递值并未按预期修改调用者中的结构,因此这似乎是64位ctypes中的错误。