1

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)
0

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Changed like you said works perfectly. Thanks @mark-tolonen. About buffer overflow, yes, you are right. I translated my 'hola' for 'hello' to post it here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.