返回介绍

7.7 指针

发布于 2024-10-13 11:25:30 字数 1776 浏览 0 评论 0 收藏 0

很多时候,指针是相对宽泛概念,并非特指 原始指针 (raw-pointer)。以 引用 (reference)为例,经编译检查后,卸去职责,在底层指令层面,与原始指针无异。

引用和原始指针是独立对象,间接( *p )操作目标。透过指针修改目标时,无需声明指针自身可变(mut),除非指针打算改变自己的指向。

  raw-pointer            reference
  ===================+=================
  *const T        &T
  *mut T        &mut T

原始指针

原始指针也分可变和不可变。无论读写都不安全,须自行负责。

fn main() {
  let mut x = 100;

  let r: *mut i32  = &mut x;
  unsafe {
    *r += 1;
    assert_eq!(*r, 101);
  }

  let r: *const i32 = &x;
  assert_eq!(unsafe{ *r }, 101);
}

可以和引用相互转换。

fn main() {
  let mut x = 100;
  let r = &mut x;

  // 引用转指针必然是安全的。
  
  let p = r as *mut i32;
  assert_eq!(unsafe{ *p }, x);

  // 指针转回引用就未必安全了。
  
  let r2: &mut i32 = unsafe{ &mut *p };  // unsafe{ & *p } -> &i32
  *r2 += 1;
  assert_eq!(x, 101);
}

可通过 usize 转换实现指针运算。也正因如此,指向无法保证。

use std::mem::size_of_val;

fn main() {
  let mut x = [1, 2, 3, 4];
  let mut p: *mut i32 = &mut x[0]; // 指针自身和目标都可变。
  
  unsafe {
    assert_eq!(*p, 1);

    p = ((p as usize) + size_of_val(&x[0])) as *mut i32; // p++
    *p += 10;
    assert_eq!(*p, 12);
  }
}

原始指针不参与对象生命周期,有可能成为悬垂指针。

#[derive(Debug)]
struct Data {
  x: i32,
}

impl Drop for Data {
  fn drop(&mut self) {
    println!("Dropping!");
  }
}

fn main() {
  let d = Data{ x: 10 };
  let p = &d as *const Data;

  {
    let _d2 = d;  // move!!!
  }         // drop!!!

  unsafe {
    println!("{:p}, {:?}", p, *p);
  }
}
$ cargo r
  Finished dev [unoptimized + debuginfo] target(s) in 0.06s
   Running `target/debug/demo`

Dropping!
0x7ffe5b385654, Data { x: 10 }   # 虽然能返回内容,但这只是因为是栈内存未被覆盖的缘故。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文