Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python ctypes - passing numpy array - odd output

I'm using ctypes and I'm passing a ndarray to a c-function. It gives me a odd output behavior. Heres some code:

C-Function:

int foo(int * foo,int N){
for(int i=0;i<N;i++){
    cout << "i " << i  << " "<< foo[i]  << endl;
    }
return 0;
}

Python:

from ctypes import *
import numpy as np
bar = cdll.LoadLibrary(".../libtest.so")
N = c_int(10)
check = np.ones(10, dtype=int)
print check
bar.foo(c_int(check.ctypes.data),N)

Output:

[1 1 1 1 1 1 1 1 1 1]
i:0 out:1
i:1 out:0
i:2 out:1
i:3 out:0
i:4 out:1
i:5 out:0
i:6 out:1
i:7 out:0
i:8 out:1
i:9 out:0

Should be all ones right? :)

I' compiling with

g++ -g -c -fPIC -O0  pythagoras.cpp 
g++ -shared -Wl,-soname=libtest.so -o libtest.so  pythagoras.o 

Anyone any ideas? I'm searching the failure now for at least 1hr and I'm having no idea what the solution is(probably something stupid)

Thanks in advance!

like image 249
toebs Avatar asked Oct 03 '22 23:10

toebs


1 Answers

Setting the dtype to a Python int will use a C long. If you're on a 64-bit platform (other than Windows), that's a 64-bit data type, which explains the interleaved 0s. You can check this by setting dtype=np.int32 vs dtype=np.int64.

Secondly, check.ctypes.data is a Python int representing a C void * pointer. Passing it as c_int isn't correct. At a minimum, use c_void_p, and define argtypes:

from ctypes import *
import numpy as np

bar = CDLL('.../libtest.so')
bar.foo.argtypes = [c_void_p, c_int]

check.ctypes defines the _as_parameter_ ctypes hook, which returns an instance of c_void_p:

N = 10
check = np.ones(N, dtype=np.int32)
print check
bar.foo(check.ctypes, N)

You can be more specific with check.ctypes.data_as, or by defining a type with np.ctypeslib.ndpointer.

By the way, foo is a C++ function, not C. You must have used extern "C". Otherwise the exported name would be mangled.

like image 76
Eryk Sun Avatar answered Oct 05 '22 23:10

Eryk Sun