Idiomatic untyped pointer


#1

I know this is not a very common situation in Rust, but what is the idiomatic way to describe a pointer pointing to memory of unknown type and size? *const c_void, *const u8 or *const ()? Personally, I prefer keeping the std::os::raw types (like c_void) as close to the FFI boundaries as possible and not cluttering my library code or exposing these types in my library’s interface.

Since in this specific case I know that these pointers are actually function pointers of unknown type, maybe I should create a type alias (e.g. type FnPointer = *const c_void)? If so, what type to create the alias for? What do you guys think?


#2

Usually *const c_void is only used when const void* appears in the C API. For opaque struct types, the typical approach is to define an empty enum, e.g. const struct Foo* would be represented as *const Foo for enum Foo {}. This retains type safety, ensuring that pointers of different types can’t be mix-and-matched without an explicit cast.


#3

Usually, I use a newtype around void.

struct my_c_struct(c_void);

Usually const c_void is only used when const void appears in the C API. For opaque struct types, the typical approach is to define an empty enum, e.g. const struct Foo* would be represented as *const Foo for enum Foo {}. This retains type safety, ensuring that pointers of different types can’t be mix-and-matched without an explicit cast.

Is this defined behavior? Foo can’t be constructed so I’d expect LLVM to assume that *const Foo must be null.


#4

It’s been discussed and rust has committed to the Void enum approach, (PR)

Just make sure the empty enum is not Copy, then it would be very simple to cause UB by mistakenly dereferencing the opaque pointer.


#5

Thanks for that. Now to update my bindings…


#6

This brings up an issue I’ve been curious about: Does Rust guarantee that function pointers and data pointers have the same representation? C notably does not guarantee this (although I believe POSIX does).


#7

Yep, it does.