Rust vs. C:为什么Rust引用String中的字符时会显示相同的内存地址?

7fyelxc5  于 2023-02-18  发布在  其他
关注(0)|答案(1)|浏览(143)

我试着去理解Rust的指针/引用系统和C的比较。我已经包含了 * 大致 * 相同的Rust和C代码以及它们的输出。代码的目的是声明一个“字符串”,声明一个指向字符串的第一个元素/字符的指针,然后为每个元素:
1.打印原始指针(内存地址)
1.打印字符本身(通过取消引用指针)
1.再次打印存储器地址(通过参考从步骤2获得的值)

所有的步骤在C中都能正常工作,但是第三步在Rust中却不能正常工作。我怎样才能在Rust中像这样操作不安全的指针算法呢?(例如创建指针;参考参考)
** rust eclipse 源**

fn main() {
    //Init String, pointer and get String length for iterator
    let my_str = String::from("York");
    let my_str_ptr: *const u8 = my_str.as_ptr();
    println!("Original string: {my_str}");

    for i in 0..my_str.len() {
        unsafe {
            //Offset pointer by i
            let chr_ptr: *const u8 = my_str_ptr.offset(i as isize);
            let chr: char = *chr_ptr as char;

            println!("Deref raw pointer: {chr}");
            println!("Raw pointer:       {chr_ptr:p}");
            println!("Ref to value:      {:p}", &chr);
        }
    }
}

** rust eclipse 量:**

Original string: York
Deref raw pointer: Y
Raw pointer:       0x561e134b8ba0
Ref to value:      0x7ffd962f665c
Deref raw pointer: o
Raw pointer:       0x561e134b8ba1
Ref to value:      0x7ffd962f665c
Deref raw pointer: r
Raw pointer:       0x561e134b8ba2
Ref to value:      0x7ffd962f665c
Deref raw pointer: k
Raw pointer:       0x561e134b8ba3
Ref to value:      0x7ffd962f665c

C来源:

#include <stdio.h>

int main(void) {
    char *my_str = "York";
    char *my_str_ptr = my_str;
    printf("Original string: %s\n", my_str);

    while (*my_str_ptr != '\0') {
        printf("Deref raw pointer: %p\n", my_str_ptr);
        printf("Raw pointer:       %c\n", *my_str_ptr);
        printf("Ref to value:      %p\n\n", &(*my_str_ptr));
        my_str_ptr++;
    }

    return 0;
}

C输出:

Original string: York
Deref raw pointer: 0x559af0d44004
Raw pointer:       Y
Ref to value:      0x559af0d44004
Deref raw pointer: 0x559af0d44005
Raw pointer:       o
Ref to value:      0x559af0d44005
Deref raw pointer: 0x559af0d44006
Raw pointer:       r
Ref to value:      0x559af0d44006
Deref raw pointer: 0x559af0d44007
Raw pointer:       k
Ref to value:      0x559af0d44007

在这个极其简单的例子中可以清楚地看到,在C中分层ref/deref操作符是很简单的,这样就可以获得值和它们的引用,然而对于rust中的char来说,情况似乎不是这样。
我怀疑这是由Rust的打印格式化程序引起的,这个问题与Rust实现指针、值和地址的方式无关。

ccrfmcuu

ccrfmcuu1#

下面的答案和代码反映了cafce 25所做的评论,它回答了我最初的问题并解决了我的困惑。
C代码和Rust代码并不等同,C代码直接作用于迭代块中的global/main()定义的变量,而Rust代码在每次迭代时都会创建一个新的局部作用域char,并正确打印。
然而,当打印单个char的内存地址时--输出显示的是局部作用域char的地址,每次for循环迭代时都会重新创建该地址;这只是碰巧编译器重用相同的堆栈地址来存储char的情况。

固定 rust eclipse 代码:

fn main() {
    let my_str = "York";
    println!("Original string: {}\n", my_str);

    //Declared mutable to allow iteration over elements
    let mut my_str_ptr = my_str.as_ptr();

    for _ in 0..my_str.len() {
        unsafe {
            println!("Pointer: {:p}", my_str_ptr);
            //Dereference my_str not a new local char
            println!("Deref pointer: {}", *my_str_ptr as char);
            //Reference dereferenced pointer to my_str, not new char
            println!("Ref derefed pointer: {:p}\n", &*my_str_ptr);
            my_str_ptr = my_str_ptr.offset(1);
        }
    }
}

固定 rust eclipse 程序输出:

Original string: York

Pointer: 0x55a9f9d0705b
Deref pointer: Y
Ref derefed pointer: 0x55a9f9d0705b

Pointer: 0x55a9f9d0705c
Deref pointer: o
Ref derefed pointer: 0x55a9f9d0705c

Pointer: 0x55a9f9d0705d
Deref pointer: r
Ref derefed pointer: 0x55a9f9d0705d

Pointer: 0x55a9f9d0705e
Deref pointer: k
Ref derefed pointer: 0x55a9f9d0705e

相关问题