Home > Net >  Calling C functions in python with ctypes
Calling C functions in python with ctypes

Time:04-01

I have a code in C that I want to use in python using ctypes.

int read_mesh(int *node,char *buf,int bufsize,int exitflag,int timeoutms)
  {
  int ndevice,locnode,retval;
 
  locnode = FROM_MESH;
  retval = readserial(&locnode,buf,bufsize,0,(exitflag & 3),timeoutms);

  if(locnode == 0)
    *node = 0;
  else
    *node = dev[locnode]->node;  // known sender
   
  return(retval);
  }

I am trying to call it using ctypes but I am stuck now and I can't run it. This is my code but I think that there is something wrong with the first two argument.

bt = ctypes.CDLL("functions.so")
bt.read_mesh.argtypes = (ctypes.POINTER(ctypes.c_int),ctypes.POINTER(ctypes.c_char),ctypes.c_int,ctypes.c_int,ctypes.c_int)

node = None
arrSv = ctypes.c_char * 32
bt.read_mesh(node,arrSv(*[b"0"]*32),ctypes.sizeof(arrSv),2,0)

In C, this is how it is called.

int nread,node;
char inbuf[32];
read_mesh(&node,inbuf,sizeof(inbuf),2,0);

I am stuck in the first two arguments. Please help me with this. Thank you so much!

CodePudding user response:

The code needs to pass the address of a ctypes-compatible object for output parameters. Currently None is passed for node which is equivalent to a C null pointer. Here's a working example:

test.c

#include <memory.h>

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

API int read_mesh(int *node, char *buf, int bufsize, int exitflag, int timeoutms)
{
    // sample output values
    *node = 123;
    memset(buf, 'A', bufsize);
    return 1;
}

test.py

import ctypes as ct

dll = ct.CDLL('./test')
dll.read_mesh.argtypes = ct.POINTER(ct.c_int), ct.c_char_p, ct.c_int, ct.c_int, ct.c_int
dll.read_mesh.restype = ct.c_int

node = ct.c_int()        # a ctypes-compatible int
buf = (ct.c_char * 32)() # a ctypes-compatible char[32]
# ctypes.byref() is equivalent to C & (take the address of).
# len() gives elements of array, ctypes.sizeof() gives number of bytes.
# Same in this case, but different answer for, say, (c_int * 5)().
dll.read_mesh(ct.byref(node), buf, len(buf), 2, 0)
print(f'{node.value=}')
print(f'{buf.raw=}')

Output:

node.value=123
buf.raw=b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
  • Related