简体   繁体   中英

Passing struct from C to Python with ctypes

I'm trying to pass a struct from C to Python but I've problems when some attribute is a 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;
}

I need get this output:

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

In test.py , the type of field2 is incorrect. ctypes.c_char * 5 is the correct ctypes syntax for a C char[5] .

Also in test.py , change foo_view.field2.value to foo_view.field2 since it will not be a pointer. Without that change, the Python code will throw an exception that isn't currently handled by the test.c code and it will just stop after the first print .

In main.c , sprintf(foo->field2, "hello"); is going to have a buffer overflow because of the null terminator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM