Python Could not read structure containing char array using Python types

I wrote a tiny dll in C, this is my .c file.

struct my_struct
{
    char arr[3];
};
__declspec(dllexport) struct my_struct func()
{
    struct my_struct m;
    m.arr[0] = 1;
    m.arr[1] = 2;
    m.arr[2] = 3;
    return m;
};
//compiled to testdll.dll

      

I tried to call the exported c function using python. This is my .py file.

from ctypes import *


class MyStruct(Structure):
    _fields_ = [("arr", c_char * 3)]


f = cdll.testdll.func
f.restype = MyStruct

for i in f().arr:
    print(i)

      

When I tried to read the array in the returned structure c, I always got random values.

But if I use int arrays instead of char arrays in .cpp and .py files, I can get the correct values ​​as expected. Why?

Error when using ctypes module to access DLL, written in the C . See this question here, I think I shouldn't be returning structs by value here because since the returned structs are implementation defined.

+3


source to share


2 answers


I was able to get the correct values ​​by declaring the return type as POINTER(MyStruct)

, so it seems like Python treats the return of a structure as returning a pointer to that structure. A more natural way to return the structure would be to return it as an out parameter. I've provided examples of both below.

As you said, usage func.restype = MyStruct

worked correctly for c_int * 3

both a member of a struct, but I found that it only func.restype = POINTER(MyStruct)

worked for both members c_char * 3

and c_int * 3

when a struct is used as a return value.

test.c

struct my_struct
{
    char arr[3];
};

__declspec(dllexport) struct my_struct func()
{
    struct my_struct m = {1,2,3};
    return m;
};

__declspec(dllexport) void func2(struct my_struct* m)
{
    m->arr[0] = 4;
    m->arr[1] = 5;
    m->arr[2] = 6;
};

      



test.py

from ctypes import *

class MyStruct(Structure):
    _fields_ = ('arr',c_char * 3),

dll = CDLL('test')

func = dll.func
func.argtypes = None
func.restype = POINTER(MyStruct)

func2 = dll.func2
func2.argtypes = POINTER(MyStruct),
func2.restype = None

x = func()
print(x.contents.arr[0],x.contents.arr[1],x.contents.arr[2])

m = MyStruct()
func2(m)
print(m.arr[0],m.arr[1],m.arr[2])

      

Output

1 2 3
4 5 6

      

+1


source


You will have a problem with Interfacing c / C ++ DLL with python if you don't use Visual Studio. From time to time, you can get off the shallow walk on your codes. The problem MinGW [I haven't used Clang] is facing is that the DLL has been generated, but its encoding is different from what is expected.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx

Here is the link of the Windows Portable Executable (PE) header structure



Only Visual Studio [at the moment] can generate Windows Shared Library executables .

The problem will not persist when using Linux systems. I don't know about Macintosh.

As in the code, you need to add a pointer to the MyStruct structure that you will use to calculate on the Dll side [this avoids the problem with the workabout].

+1


source







All Articles