NonNull::dangling()
существует в Rust, чтобы иметь возможность временно инициализировать значение NonNull
, прежде чем присвоить ему реальное значение. Вы не можете использовать null
в качестве временного, потому что это NonNull
, и оно будет отображать неопределенное поведение.
Например, этот совершенно безопасный (я полагаю) самоссылающийся пример требует 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
}
}
Ваш вопрос об эквиваленте NonNull::dangling()
в C заключается в том, что в C нет NonNull
, поэтому для этих видов временной инициализации вы можете NULL
или просто оставьте его унитализованным, пока не получите правильное значение.
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;
}
Тем не менее, я уверен, что есть и другие варианты использования NonNull::dangling
, кроме временной инициализации самоссылающихся структур. Для тех, кто вам может понадобиться эквивалентный C код. Эквивалентный код C был бы (в виде макроса, поскольку он принимает тип в качестве аргумента):
#define DANGLING(T) ((T*)alignof(T))
То есть указатель должен быть как можно ближе к нулю при соблюдении выравнивания данного типа , Идея состоит в том, что в большинстве архитектур указатель NULL фактически находится по адресу 0, и первые несколько килобайт никогда не отображаются, так что среда выполнения может отлавливать разыменования NULL. А поскольку максимальные требования к выравниванию обычно составляют всего несколько байтов, это никогда не будет указывать на допустимую память.