Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading C structures in Python with ctypes

Tags:

python

c

ctypes

I'm using ctypes to call foreign functions in Python3.

The C function is supposed to return the pointer to the structure:

struct sLinkedList {
    void* data;
    struct sLinkedList* next;
 };

typedef struct sLinkedList* LinkedList;

And the function as it is defined in C is as follows.

LinkedList IedConnection_getServerDirectory (IedConnection  self, IedClientError *  error, bool     getFileNames )  

So I have my Python3 code as follows:

from ctypes import *

...

class LinkedList(Structure):
    pass

LinkedList._fields_ = [("data",c_void_p), ("next",  POINTER(LinkedList))]

...

IedConnection_getServerDirectory=dlllib.IedConnection_getServerDirectory
IedConnection_getServerDirectory.argtypes=[c_void_p, c_void_p]
IedConnection_getServerDirectory.restype = c_int
LogicalDevicesPtr = IedConnection_getServerDirectory(IedConnection,iedClientError)

The IedConnection parameter is retrieved by other function as pointer, and I'm pretty sure it works fine. Also I can see that function itself works fine (it initiates communications, that could be seen in Wireshark).

Then I try to get the information as result of function:

LogicalDevicesList_p = cast(LogicalDevicesPtr,POINTER(LinkedList))

LogicalDeviceList = LogicalDevicesList_p.contents

This lines passes and the following line fails:

Rdata = LogicalDeviceList.data

with "Segmentation fault: 11"

I suppose the problem if with types definitions, but I have no idea where the mistake is. Could anyone help?

like image 680
Alex Avatar asked Aug 15 '16 17:08

Alex


1 Answers

Well, looks like i've solved it by myself:

IedConnection_getServerDirectory.restype = c_int

is incorrect and shall was changed to:

IedConnection_getServerDirectory.restype = c_void_p

And it started working fine already.

But additionally I've added third argument to function call to make it more neat:

IedConnection_getServerDirectory.argtypes=[c_void_p, c_void_p, c_bool]
LogicalDevicesPtr = IedConnection_getServerDirectory(IedConnection,iedClientError,c_bool(False))
like image 106
Alex Avatar answered Oct 19 '22 21:10

Alex