如何以字节为单位获取指针偏移量? [英] How to get pointer offset in bytes?

查看:41
本文介绍了如何以字节为单位获取指针偏移量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然 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.

isizeusize 是通用的字节大小的指针类型 :)

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆