我有一个指针buf:*const T
,指向一个分配了n
个元素的T
的起始位置,并定义以下检查:
let in_alloc = buf <= ptr && ptr < unsafe { buf.add(n) };
你指出in_alloc是否保证对于位于buf分配范围内的任何ptr都为true,并且在任何其他情况下都为false? 我们可以假设 ptr 是一个有效的指向T对象的指针(因此不会是错位/空/悬挂),但它可能是来自与buf不同的分配。 最后,我们可以假设T不为零大小。
我有一个指针buf:*const T
,指向一个分配了n
个元素的T
的起始位置,并定义以下检查:
let in_alloc = buf <= ptr && ptr < unsafe { buf.add(n) };
回答标题,比较任意两个指针是明确定义的,因为指针实现了Ord
。
由于指针被完全排序,问题的主体可以轻松地从此中得出。你有一组不同的指针,从buf + 0
开始,以buf + (n - 1)
结束。如果ptr
小于buf
,它不能等于它们中的任何一个。如果ptr
大于buf + (n - 1)
,它也不能等于它们中的任何一个。如果ptr
是其中之一,那么这两个表达式都计算为真。
你可以使用Range
来绕过一些问题:
let end = unsafe { buf.add(n) };
let in_alloc = (buf..end).contains(ptr);
这通常被用来检查一个片段是否包含指针,例如这里。
buf.add(n)
指向的地址最多比buf
指向的对象的分配多1个字节,就会返回您期望的值。有关详细信息,请参见https://doc.rust-lang.org/1.59.0/std/primitive.pointer.html#method.offset。buf
指向了一个大小为n
个元素的T类型的分配内存。因此,buf.add(n)
是已定义的行为。 - orlp
std::less
为指针提供了完全排序,但这还不足以实现检查某个指针是否属于已分配的块。 - Language LawyerT
是对齐的。这就是 Kevin 上面提到的交错的原因。对于指向 T 的对齐指针的总序列不允许重叠范围。(与非对齐指针不同,编译器可以按照明显的方式对它们进行排序,但严格限制在buf + 0
和buf + 1
之间,因为它想成为一个垃圾编译器。) - GManNickGRange<*const T>
将排序与算术相关联。这在文档示例中明确利用,例如切片as_ptr_range
。更普遍地说,Rust 指针(主要是由于 LLVM)实现了类似整数的语义(有时过于热衷于优化)。UCG WG 中有一些关于使其更加正式的讨论(尽管目前已经停滞不前)。 - GManNickG(x..y).contains(p)
来检查切片成员资格,或者p.wrapping_add
后跟比较来检查包装。当正式规范最终出现时,它需要提供显式而不是隐式的连接。我会编辑答案并提供一些示例。 - GManNickG