0

I see a problem from one Stackoverflow question. It is described below:

I have a C++ function which returns a raw float pointer, and another C++ function which accepts a raw float pointer as an argument. Something like:

float* ptr = something;
float* get_ptr(void) { return ptr; }
void use_ptr(float* ptr) { do_work(ptr); }

I want to be able to pass around pointers using Python. Something like this:

import my_native_functions as native
ptr = native.get_ptr()
native.use_ptr(ptr)

I am using pybind11 to create my native python module but I don't know how to create the bindings for the get_ptr() function. If I just do the following:

PYBIND11_MODULE(my_native_functions, m)
{
    m.def("get_ptr", &get_ptr);
    m.def("use_ptr", &use_ptr);
}

the get_ptr() function returns a Python Float object. I guess this makes sense because there are no pointer types in python. However, because this is now a simple Float, when I call the use_ptr() function and iterate over the pointer in C/C++, only the first element of the array is correct. The rest are garbage. To fix this, in C++, I have to cast my pointer to/from std::size_t. By doing this, everything works just fine.

However, I would like to ask: Is there a "right way" of achieving the above without the casting to/from std::size_t with pybind11?

The above is the whole problem description that comes from AstrOne's question:Returning and passing around raw POD pointers (arrays) with Python, C++, and pybind11.

My question is "To fix this, in C++, I have to cast my pointer to/from std::size_t", how should this cast be done? Can here give me a example or more detailed explanation? I don't quite understand.

Nimrod
  • 2,908
  • 9
  • 20

1 Answers1

0

Replace the float* type with std::uintptr_t. See below

#include <cstdint>

float* ptr = something;
std::uintptr_t get_ptr() { return reinterpret_cast<std::uintptr_t>(ptr); }
void use_ptr(std::uintptr_t ptr) { do_work(reinterpret_cast<float*>(ptr)); }

No pointer types will be exposed to pybind11 now. What is doing here is just cast a pointer type to a integral type, which has no difference in binary representation.

Aside: std::size_t would be Ok in most platforms. As per cppref:

On many platforms (an exception is systems with segmented addressing) std::size_t can safely store the value of any non-member pointer, in which case it is synonymous with std::uintptr_t.

Nimrod
  • 2,908
  • 9
  • 20