c - 是否可以使用Rust中的指针访问结构的元素?

标签 c struct rust

在C语言中,我们可以通过指针访问结构的各个元素。我们如何在Rust中做同样的事情?
下面的代码显示了如何使用C中的指针访问元素。

#include <stdio.h>
#include <stdlib.h>

typedef struct __attribute__ ((packed)) {
    int a;
    int b;
    int c;
} Data;

Data* new_data(const int a, const int b, const int c) {
     Data* data = malloc(sizeof(Data));
     data->a = a;
     data->b = b;
     data->c = c;
     return data;
}

int main(int argc, char* argv[]) {
    Data* data = new_data(23, 35, 12);

    // accessing elements via pointers
    printf("\n --- Using pointers ---\n");
    printf("a: %d\n", *((int*)data + 0));
    printf("b: %d\n", *((int*)data + 1));
    printf("c: %d\n", *((int*)data + 2));

    // using pointer magic
    printf("\n --- Using pointer magic ---\n");
    printf("b: %d\n", *((int*)((char*)data + sizeof(int))));
    printf("c: %d\n", *((int*)((char*)data + sizeof(int) * 2)));

    // accessing elements via name
    printf("\n --- Using names ---\n");
    printf("a: %d\n", data->a);
    printf("b: %d\n", data->b);
    printf("c: %d\n", data->c);

    free(data);
    return 0;
}
上面的代码是使用gcc编译的,我知道它也是特定于平台的,但这与我无关。
以下是我目前在Rust中拥有的东西。
struct Data<T> {
    el: Vec<T>
}

impl <T> Data<T> where T: Copy {
    fn new(a: T, b: T, c: T) -> Self {
        let mut s = Self { el: Vec::with_capacity(3) };
        s.el.push(a);
        s.el.push(b);
        s.el.push(c);
        return s;
    }

    fn get_a(&self) -> T { self.el[0] }
    fn get_b(&self) -> T { self.el[1] }
    fn get_c(&self) -> T { self.el[2] }
}

fn main() {
    let mut data = Data::new(23, 35, 12);
    println!("data capacity: {:?}", data.el.capacity());

    println!("a: {:?}", data.get_a());
    println!("b: {:?}", data.get_b());
    println!("c: {:?}", data.get_c());
}
我想能够使用
struct Data<T> {
    a: T,
    b: T,
    c: T
}
并通过它们的索引访问每个元素。

最佳答案

在一般情况下,今天在Rust中无法正确执行此操作。 但是,您的特定结构避免了一些最严重的问题,因此可以安全地将整个结构作为借来的切片(&[T])借用。为此,您需要做三件事:

  • 标记结构repr(C)而不是repr(packed) !压缩的结构是未对齐的,并且引用必须始终正确对齐。
  • 检查结构的大小不大于isize::MAX
  • 使用 slice::from_raw_parts &[T]借用&Data<T>

  • 有关声音合理性的逐点说明,请参阅Is it legal to cast a struct to an array?
    #[repr(C)]
    struct Data<T> {
        pub a: T,
        pub b: T,
        pub c: T,
    }
    
    impl<T> Data<T>
    where
        T: Copy,
    {
        fn new(a: T, b: T, c: T) -> Self {
            Data { a, b, c }
        }
    
        // N.B. you could also implement `AsRef<[T]>` and/or `Borrow<[T]>`, which
        // are used frequently in generic code
        fn as_slice(&self) -> &[T] {
            assert!(std::mem::size_of::<Self>() <= isize::MAX as _);
            // This `unsafe` block was copied from Stack Overflow without proving
            // its use is correct in this context, so it's almost certainly wrong
            unsafe { std::slice::from_raw_parts(self as *const _ as *const T, 3) }
        }
    }
    

    关于c - 是否可以使用Rust中的指针访问结构的元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64307184/

    相关文章:

    c - 如何在gcc中使用struct?

    C++在多个对象实例之间共享一个变量

    c - typedef、结构和类型兼容性

    rust - 如何编写将一个字节拆分为用户指定计数的位元组的宏?

    rust - 派生 Serde 的序列化或反序列化强制泛型类型可序列化,尽管它不需要是

    c - 找到一个符号和其他 "unresolved external symbol"

    c - 为什么我们在初始化一个指向整数的指针时,在整数变量前使用 "&"?

    c++ - 如何修改按值传递的原始变量的内容?

    c - 如何正确地将内存分配给存储在结构中的动态整数数组?

    pattern-matching - Rust 中无法访问的模式匹配