c - 是否可以使用 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
中借 a 。&[T]
&Data<T>
有关为什么这是合理的逐点证明,请参阅将结构强制转换为数组是否合法?
#[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# - 验证 TCP 消息的传递
- android - Android Studio 无法识别 Windows 10 上的原始文件
- python - Selenium + Python:通过 click() 的下一个按钮
- google-app-maker - 列和行中的 Appmaker 数据
- sql - Aster UPDATE 列不存在
- python - Redisearch不能在集群中工作?
- c# - 在winforms中将项目添加到ListView的特定列
- react-final-form - 如何处理 react-final-form 中的嵌套表单?
- xamarin - iOS 设置应用程序中不显示设置包
- amazon-web-services - 创建 SageMaker 模型时出现 ValidationError