If it exists, it should satisfy the following properties:
void *
NULL
At first I thought I could do something like (NULL + 1)
or (void *)1
, but these appear to be problematic. The former uses pointer arithmetic on NULL
which I believe is undefined behavior. The second relies on the fact that NULL
does not have physical address 1. (i.e. it is entirely possible that (void *)0 == (void *)1
)
NonNull::dangling()
exists in Rust to be able to temporarily initialize a NonNull
value before giving it the real value. You cannot use null
as the temporary because it is a NonNull
and it would render Undefined behavior.
For example this perfectly safe (I guess) self-referentiable example requires NonNull::dangling()
:
struct SelfRef {
myself: NonNull<SelfRef>,
data: String,
}
impl SelfRef {
fn new(data: String) -> Pin<Box<SelfRef>> {
let mut x = Box::pin(SelfRef {
myself: NonNull::dangling(),
data,
});
x.myself = unsafe { NonNull::new_unchecked(x.as_mut().get_unchecked_mut()) };
x
}
}
About your question of the equivalent to NonNull::dangling()
in C is that, in C there is no NonNull
, so for these kinds of temporary initialization you can NULL
or just leave it unitilizalized until you have the proper value.
struct SelfRef {
SelfRef *myself;
//...
};
struct SelfRef *new_selfref() {
struct SelfRef *x = malloc(sizeof(struct SelfRef));
//Here x->myself is uninitialized, that is as good as dangling()
x->myself = x;
return x;
}
That said, I'm sure that there are other uses of NonNull::dangling
other than temporary initialization of self-referentiable structs. For those you may actually need an equivalent C code. The equivalent C code would be (in macro form as it takes a type as argument):
#define DANGLING(T) ((T*)alignof(T))
That is, a pointer as near to zero as possible while complying with the alignment of the given type. The idea is that in most architectures the NULL pointer is actually at address 0, and the first few kilobytes are never mapped, so that the runtime can catch NULL dereferences. And since the maximum alignment requirements are usually just a few bytes, this will never point to valid memory.