Create a nonnull UnsafeRawPointer of underlying rawValue 0

Issue

If we use .init(bitPattern:) and pass 0 here. We'll get a nil value.

An alternative way is use unsafeBitCast(0, to: UnsafeRawPointer).

Unfortunately, a warning will be emitted and I'm use werror here.

'unsafeBitCast' from 'Int' to 'UnsafeRawPointer' can be replaced with 'bitPattern:' initializer on 'UnsafeRawPointer'

They are actually not interchangeable. Since .init(bitPattern:) will return nil for 0.

Is there any other solutions or how can I disable the warning emitted by compiler here.

Context:

I'd like the pointer to be invalid at first and assign it to be valid later. But I do not want to use UnsafeRawPointer! here

Another solution I can think of is by Pointer calculation. But it is less elegant than unsafeBitCast.

eg.

let a = 1 // "a" can be any number except 0
let b = UnsafeRawPointer(bitPattern: a)! - a

Why not? This sounds like exactly what that type is for.

1 Like

I know the best practices and the consequence here.

But for some special low-level purpose, I need the feature and is trying to make compiler happy.

Here is the final answer I found in the end - use unsafeBitCast without the annoying warning.

unsafeBitCast(Double.zero, to: UnsafeRawPointer.self)
// Or any other 64-bit and zeroable struct
// eg. struct A { let value: Int }

I think Swift choose this behavior of UnsafeRawPointer.init for a reason. A pointer with an address of 0 is invalid on almost every machine. So maybe it can help to prevent you from accidentally forgetting to re-assign that pointer.

Out of curiosity, why not just use UnsafeRawPointer?, it's just as efficient as plain UnsafeRawPointer in terms of memory usage.

2 Likes

Just to avoid ? and seek for absolute performance here.

Again I know the best practices and the consequence. Just try to workaround the compiler limitation/warning.

As a general rule, there is no performance overhead to UnsafeRawPointer? vs. UnsafeRawPointer. UnsafeRawPointer? has exactly the same in-memory layout as UnsafeRawPointer, and the .none case (nil) is simply represented as 0x0 in memory—that is, it is exactly equivalent to C's null pointer.

The only time you might see any sort of runtime overhead (ignoring generics where things might not be fully specialized) would be when testing for nil, but the overhead there is again exactly the same as the overhead you'd have checking for NULL in C.

(Giant asterisk: when building with optimizations off, you will likely see additional runtime overhead, but that's just what "optimizations off" means and the same can be said of equivalent C code.)

7 Likes

When building with optimizations there still will be a test instruction that branches to a trap when the pointer is nil. The unsafelyUnwrapped property is a way to unwrap it without any checks at all (in -O builds).

1 Like

Thanks for the clarification. I'll use UnsafeRawPointer? then.

That trap is only relevant when force-unwrapping the optional value. If you don't force-unwrap it, the trap instruction shouldn't be emitted.

1 Like