如何以字节为单位获取指针偏移量? [英] How to get pointer offset in bytes?
问题描述
虽然 Rust 中的原始指针具有 offset
方法,这只会增加指针的大小.如何以字节为单位访问指针?
While raw pointers in Rust have the offset
method, this only increments by the size of the pointer. How can I get access to the pointer in bytes?
在 C 中是这样的:
var_offset = (typeof(var))((char *)(var) + offset);
推荐答案
TL;DR:根据 RFC-2582.
特别是,引用必须对齐且可取消引用,即使它们被创建但从未使用过.
In particular, references must be aligned and dereferencable, even when they are created and never used.
也有讨论表明,由于使用了 getelementptr inbounds
,字段访问本身会施加额外的要求,但所提议的 &raw
没有解决,请参阅 offsetof
woes 在 RFC 的底部.
There are also discussions that field accesses themselves impose extra requirements not solved by the proposed &raw
, due to usage of getelementptr inbounds
, see offsetof
woes at the bottom of the RFC.
来自答案我链接到您之前的问题:
From the answer I linked to your previous question:
macro_rules! offset_of {
($ty:ty, $field:ident) => {
// Undefined Behavior: dereferences a null pointer.
// Undefined Behavior: accesses field outside of valid memory area.
unsafe { &(*(0 as *const $ty)).$field as *const _ as usize }
}
}
fn main() {
let p: *const Baz = 0x1248 as *const _;
let p2: *const Foo = ((p as usize) - offset_of!(Foo, memberB)) as *const _;
println!("{:p}", p2);
}
我们在p2
的计算中可以看到,一个指针可以无痛地转换为一个整数(这里是usize
),对其进行算术运算,然后得到结果被强制转换回一个指针.
We can see on the computation of p2
that a pointer can be converted painless to an integer (usize
here), on which arithmetic is performed, and then the result is cast back to a pointer.
isize
和 usize
是通用的字节大小的指针类型 :)
isize
and usize
are the universal byte-sized pointer types :)
是 RFC-2582 被接受,offset_of!
的这个实现是我最好的选择:
Were RFC-2582 to be accepted, this implementation of offset_of!
is my best shot:
macro_rules! offset_of {
($ty:ty, $field:ident) => {
unsafe {
// Create correctly sized storage.
//
// Note: `let zeroed: $ty = ::std::mem::zeroed();` is incorrect,
// a zero pattern is not always a valid value.
let buffer = ::std::mem::MaybeUninit::<$ty>::uninit();
// Create a Raw reference to the storage:
// - Alignment does not matter, though is correct here.
// - It safely refers to uninitialized storage.
//
// Note: using `&raw const *(&buffer as *const _ as *const $ty)`
// is incorrect, it creates a temporary non-raw reference.
let uninit: &raw const %ty = ::std::mem::transmute(&buffer);
// Create a Raw reference to the field:
// - Alignment does not matter, though is correct here.
// - It points within the memory area.
// - It safely refers to uninitialized storage.
let field = &raw const uninit.$field;
// Compute the difference between pointers.
(field as *const _ as usize) - (uninit as *const_ as usize)
}
}
}
我已经评论了每一步,并说明了我认为它们合理的原因,以及为什么有些替代方案不是——我在不安全代码中大力鼓励这一点——希望没有遗漏任何东西.
I have commented each step with the reasons I believe they are sound, and why some alternatives are not -- something I encourage heavily in unsafe code -- and hopefully not missed anything.
这篇关于如何以字节为单位获取指针偏移量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!