C integration: casting UnsafeRawPointer to UnsafeMutablePointer<T?>?

Hi,

I want to call a C function that would return a fresh pointer in void **penv argument. So I created a var env_ptr: UnsafeMutableRawPointer? initialized with nil value and passed it to the function. It went right and I got that pointer in env_ptr.

But now I need to transfer the pointer to another variable with UnsafeMutablePointer<T?>? type in order to use the result in other functions.
What is the proper way for the pointer transfer? I tried it several ways without luck.

Assuming that env_ptr points to a single instance of T?, it would be

let anotherVariable = env_ptr?.assumingMemoryBound(to: T?.self)

but that assumption is very suspicious, because you cannot make optional structs in C


Assuming env_ptr points to an instance of T, you would have to copy it to another chunk of memory

let anotherVariable: UnsafeMutablePointer<T?>?
if let env_ptr = env_ptr {
    anotherVariable = UnsafeMutablePointer<T?>.allocate(capacity: 1)
    anotherVariable?.initialize(to: env_ptr.assumingMemoryBound(to: T.self).pointee)
} else {
    anotherVariable = nil
}
3 Likes

Thanks, it works. Your solution looks so straighforward after first reading. I wonder why I was not able to assemble it by myself.

I want to call this out as very important: UInt64? is not the same memory layout as UInt64. Specifically, the former is 9 bytes long, while the latter is only 8 bytes long.

If the API you're passing this to really does expect an optional, then you can't safely do the bind manoeuvre and you have to copy. There is one set of exceptions: pointers. In Swift, the various pointer types are layout compatible with their optional ones.

1 Like

Yeah I encountered the problem of optionals and pointers. No, C API I want to use does not handle optionals they just don't apply const qualifier on arguments which are not mutated.
Anyway I used the following solution to extract the inner value of optional: &jni_env!.pointee where jni_env is of UnsafeMutablePointer<JNIEnv?>? The C function I call expects JNIEnv * argument type.