user39602 user39602 - 4 months ago 18
Python Question

Linking pointer arguments from a C function with a ctype argument in python script

The following is a simple code showing division of a number:

//pointer.h
#include<stdio.h>
int divide(int , int , int *);

//pointer.c
#include<stdio.h>

__declspec(dllexport) int divide(int a, int b, int *remainder)

{
int quot = a / b;
remainder = a % b;
return quot;
}


As shown in the pointer.c, remainder is a pointer type argument whose value will be calculated in the function itself. Can anyone tell me how to get the value linked from this function to the python script as written below:

//python script
import ctypes as C
from ctypes import *
mydll=CDLL('pointer.dll')
mydll.divide.argtypes=(C.c_int,C.c_int,C.POINTER(C.c_int))
mydll.divide.restype=C.c_int


The below is the error that I'm getting.




mydll.divide(4,32,3)
Traceback (most recent call last):
File "", line 1, in
mydll.divide(4,32,3)
ctypes.ArgumentError: argument 3: : expected LP_c_long instance instead of int



Answer

Edit

It looks like you're calling your wrapped divide function with three integer arguments (mydll.divide(4,32,3)). That won't work. See the below code for how you probably want to specify the third argument. The rest of my post may be unnecessary, but I'm leaving it anyway for any future readers with different problems.


I'd first make sure you're compiling your DLL with the same bitness as your python distribution (e.g. 32 vs. 64 bit).

Next, your code has an error in that remainder = a % b; should be *remainder = a % b; (Presumably you're working from here.)

Lastly, the following code works for me (under Linux, so using gcc and .so files instead of .dll files):

pointer.c

#include<stdio.h>

int divide(int a, int b, int *remainder)
{
    int quot = a / b;    
    *remainder = a % b;
    return quot;
}

test.py

import ctypes as C
from ctypes import *
mydll=CDLL('pointer.so')
mydll.divide.argtypes=(C.c_int, C.c_int, C.POINTER(C.c_int))
mydll.divide.restype=C.c_int

rem = C.c_int()
res = mydll.divide(10, 3, rem)

print(res, rem.value)

When run, this correctly prints (3, 1).


Notes:

  • Using gcc, this was compiled with: gcc -g -Wall -shared -fPIC -I/usr/include/python2.7/ pointer.c -o pointer.so
  • I was able to remove the __declspec because gcc exports all symbols by default, if you're using a different compiler, you may need to leave it in.
  • I didn't use a .h file
Comments