简体   繁体   中英

Difficulty returning a float from Ctypes

I'm currently trying to write a simple wrapper for some C++ code so I'll be able to pass in some signal data, do a GPU operation on it and send it back. For the moment, I've cut out all GPU elements because I'm having trouble getting ctypes to return anything other than an integer.

I should preface the following by saying that I'm not sure of the severity of this decision, but I've only managed to make ctypes recognize C++ functions by wrapping the C++ functions in C functions. As my misadventures in attempting to return floats have continued, I've become aware that whatever the source of error is can definitely tell the difference between numbers that come from C++ and numbers that come from C. I'll return to this point later.

extern "C" float* giveLotsZeroes(int length) {
    float* list2 = (float*)malloc(sizeof(float)*length);
    for (unsigned int i = 0; i < length; i++) list2[i] = 0;
    return list2;
}

This is one of my example C++ functions that I used to test the functionality of returning floats, in file "kernal.cu". It's passed around to C with extern float* giveLotsZeroes(int length); and __declspec(dllexport) float* giveLotsOfZeroes(int length); defined in "chead.h" (note the Of in the middle of the function name to differentiate them). Finally, float* giveLotsOfZeroes(int length) { return giveLotsZeroes(length); } float* giveLotsOfZeroes(int length) { return giveLotsZeroes(length); } is defined in Source.c which includes chead.h, and the linker seems to have no issue compiling this to a multi-threaded dll. I have a similar iteration of this that returns a list of zeroes as integers, which functions perfectly fine, so much so that I've implemented it in GPU errorhandling, and with every single line of GPU code seeming to cause an error, I have reason to believe the error handling implementation works fine, with an exception I'll get to later.

When trying to return a list of integers of length 128, I had used numpy's ctypeslib library to great success, with

accelerator.getLastErrorCode.restype = np.ctypeslib.ndpointer(dtype=ctypes.c_int,shape=(128,))
accelerator.getLastLineExecuted.restype = np.ctypeslib.ndpointer(dtype=ctypes.c_int,shape=(128,))

and this works fine, however if I replace 128 with my length variable "length" and ctypes.c_int with ctypes.c_float, python returns a single integer usually somewhere between 1e8 and 1e10. With such odd results, I tried returning single floats too, which yielded similar results, although one might suppose less egregiously as a single value function was also returning a single value. Of interest, when I use the np.ctypeslib.ndpointer method of defining restypes, the python type function still claims the result is a numpy.ndarray but will complain if you treat it like one. I've tried alternatively defining the restypes of this function or variations on the function as ctypes.c_float*length or ctypes.POINTER(ctypes.c_float*length) but with no success.

In fact, I'd made two functions that return single zeroes, one which returned it from C++ to C to python, and one that did it directly from C, and made both of them print their zeroes to console to confirm that neither C was having an issue, nor was C having an issue with C++'s zero, but by the time they reached python, C's zero had become 1 (which I later discovered to be the case no matter what C tried to return) and C++'s zero had become a consistent 164. A friend recommended changing every instance of 0 to 0.0f which changed the 164 to the standard random large number.

The only issue I'd encountered with the error handling, having said I'd get to it later, is that in one singular but repeatable odd instance, a 700 managed to come out of a function that was only supposed to be able to return number from 0 to 29. Not sure what possible link this could have to other errors, but if it helps, it helps.

I've included my code in the following pastebin, but please note large sections of the python code are simply tests of what works as expected and what does not.

https://pastebin.com/j7gfiKA6

Your return values is ctypes.POINTER(ctypes.c_float) :

>>> from ctypes import *
>>> dll = CDLL('test')
>>> dll.giveLotsZeroes.argtypes = c_int,
>>> dll.giveLotsZeroes.restype = POINTER(c_float)
>>> x = dll.giveLotsZeroes(100)
>>> x
<__main__.LP_c_float object at 0x0000022DE407F948>
>>> x[0]
0.0
>>> x[99]
0.0

You can also get the whole array with bounds checking with:

>>> a = cast(x,POINTER(c_float*100)).contents
>>> a
<__main__.c_float_Array_100 object at 0x0000022DE45A5CC8>
>>> a[0]
0.0
>>> a[99]
0.0
>>> a[100]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: invalid index

Convert to a Python list:

>>> list(a)
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM