使用ctypes将结构从C传递到Python

时间:2019-10-02 16:51:55

标签: python c ctypes

我正在尝试将struct从C传递给Python,但是当某些属性是char *时遇到问题

test.h

typedef struct _FOO 
{
    int field1;
    char field2[5];
    int  whatever;
 } FOO, *PFOO;

 void CallPythonFunction(PFOO foo);

test.c

PyObject *module_name, *plugin, *PyTargetFunction, *ppresult, *pargs;
void CallPythonFunction(PFOO foo)
{
    // Set PYTHONPATH TO working directory
    setenv("PYTHONPATH",dir_python_modules,1);

    // Initialize the Python Interpreter
    Py_Initialize();
    module_name = PyString_FromString((char*)"test");

    // Load the module object
    if ((plugin = PyImport_Import(module_name)) == NULL) {
        PyErr_Print();
        printf("Error: PyImport_Import\n");
        return -1;
    }

    PyTargetFunction = PyObject_GetAttrString(plugin, (char*)"some_function");
    pargs = PyTuple_Pack(1
        //, PyLong_FromUnsignedLong((unsigned int) validacion)
        , PyLong_FromVoidPtr(foo)
        );

    ppresult = PyObject_CallObject(PyTargetFunction, pargs);
}

test.py

import ctypes
POINTER = ctypes.POINTER

class _PyFoo(ctypes.Structure):
    _fields_ = [
        ('field1', ctypes.c_int),
        ('field2', ctypes.c_char_p),
        #('field2', POINTER(ctypes.c_char), # not work either
        ('whatever', ctypes.c_int)
        ]

def some_function(foo):
    foo_view = _PyFoo.from_address(foo)

    print("foo.field1: ", foo_view.field1)
    print("foo.field2: ", foo_view.field2.value)
    print("foo.whatever: ", foo_view.whatever)
    pass

main.c

int main(int argc, char *argv[])
{
    PFOO foo = malloc(sizeof(FOO));
    foo->field1 = 5;
    sprintf(foo->field2, "hello");
    foo->whatever = 3;
    CallPythonFunction(foo);

    return 0;
}

我需要得到以下输出:

('foo.field1: ', 5)
('foo.field2: ', 'hello')
('foo.whatever: ', 3)

1 个答案:

答案 0 :(得分:2)

test.py中,field2的类型不正确。 ctypes.c_char * 5是C char[5]的正确ctypes语法。

还要在test.py中,将foo_view.field2.value更改为foo_view.field2,因为它不会成为指针。没有该更改,Python代码将引发test.c代码当前未处理的异常,并且它将在第一个print之后停止。

main.c中,由于空终止符,sprintf(foo->field2, "hello");将发生缓冲区溢出。