问题描述
虽然 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.
特别是,引用必须对齐且可取消引用,即使它们被创建但从未使用过.
也有讨论表明,由于使用了 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.
这篇关于如何以字节为单位获取指针偏移量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!