Struct 确定哪些数据包含已为其指定结构的变量

Struct 确定哪些数据包含已为其指定结构的变量,struct,rust,Struct,Rust,如果我们有以下代码: struct Person { age: i32 } fn main() { let person = Person{age : 52}; } 我知道如何使用struct和person变量中的所有内容 它是指向结构的第一个元素的指针吗?(因为所有元素都是连续的(?),所以编译器将知道所有元素的位置) 编辑:从生锈的角度来看,person包含实际的struct,因此在生锈代码中让person=person{age:52}变量person不是指针,也不包含

如果我们有以下代码:

struct Person {
    age: i32
}

fn main() {
    let person =  Person{age : 52};
}
我知道如何使用struct和person变量中的所有内容

它是指向结构的第一个元素的指针吗?(因为所有元素都是连续的(?),所以编译器将知道所有元素的位置)

编辑:从生锈的角度来看,
person
包含实际的
struct
,因此在生锈代码
中让person=person{age:52}变量
person
不是指针,也不包含指针。但是,它可以实现为指针,如下面的LLVM IR所示。因此,Rust代码可以转换为LLVM IR,其中
%person
实际上是指向结构的第一个元素的指针。请注意,可以优化该IR,以使实际数据最终进入寄存器,因此不一定在堆栈上

main
的LLVM IR如下所示:

; playground::main
; Function Attrs: nonlazybind uwtable
define internal void @_ZN10playground4main17h5b277f290810a924E() unnamed_addr #1 !dbg !315 {
start:
  %arg0.dbg.spill = alloca i32*, align 8
  %_11 = alloca i32*, align 8
  %_10 = alloca [1 x { i8*, i64* }], align 8
  %_3 = alloca %"std::fmt::Arguments", align 8
  %person = alloca i32, align 4
  call void @llvm.dbg.declare(metadata i32* %person, metadata !319, metadata !DIExpression()), !dbg !328
  store i32 52, i32* %person, align 4, !dbg !329
  // ...
}
  • %person=alloca i32,align 4为
    i32
    分配空间(因此
    person
    是指针)
  • store i32 52,i32*%person,align 4
    将整数
    52
    存储到该指针中。代码
    i32*%person
    表示
    %person
    属于
    i32*
    类型,因此还是指向整数的指针
例如,如果将结构更改为类似于
struct Person{age:i32,thing:bool}
,则相应的IR将是
%Person=alloca{i32,i8},align 4
,因此现在它是指向
{i32,i8}
类型的结构的指针

现在存储整数52需要进行一些转换:

%0 = bitcast { i32, i8 }* %person to i32* // cast %person to i32*
store i32 52, i32* %0, align 4
person变量中到底有什么

“内部”唯一的内容是
age
,总共有4个字节

它是指向结构的第一个元素的指针吗

不,它不是指针。实际上,它只是值本身,这意味着它将存储在当前帧/函数的堆栈中(如果可观察的行为没有改变,编译器可能会将其完全从内存中删除,甚至不使用它,但这是一种优化:从概念上讲,变量放在堆栈中)

(因为所有元素都是连续的(?),所以编译器将知道所有元素的位置)


大多数编译语言中的编译器总是知道所有类型的确切布局(特殊情况除外)。这就是为什么可以提前用这些语言进行许多优化。这些信息通常在系统编程语言中被丢弃,这就是为什么它们通常不支持反射,也就是为什么很难将它们反编译回源代码。

这个答案是误导性的:
person
变量不包含指针,它包含
person
结构,即实际数字。数字存储的位置取决于优化级别——在更高的优化级别上,它很可能最终会出现在寄存器中,或者被完全消除。
alloca
指令和生成的指针是编译器使用的中间表示的工件。最终的表示形式,即实际的机器代码,可能无法区分
Person
i32
。虽然有人可能会认为
Person
存储在堆栈上时,在某种意义上是一个指针,因为处理器必须取消引用堆栈指针才能访问它,这同样适用于
i32
,通常没有人会声称
i32
变量以某种方式持有“指针”。LLVM IR是编译器的一个实现细节。说
person
“包含指针”是不正确的,因为这会让OP认为Rust结构是像Java或Python对象一样实现的,其中变量真正包含对堆分配对象的引用。很明显,
person
包含实际数据:您可以获取
person
的地址,然后将其转储,以在那里找到数字52,而不是指针。CPU可以使用堆栈指针访问该数据,但这适用于任何不在寄存器中且不是变量属性的数据。@ForceBru问题不在于LLVM IR如何表示堆栈中的对象,也不在于典型的体系结构如何使用堆栈寄存器和偏移寻址。即使没有任何优化,变量本身也永远不会是指针。很明显,LLVM IR是一个实现细节——从您的答案(编辑之前)中根本不清楚,这给人一种完全相反的印象,并且错误地表示了rust变量的语义。您的答案清楚地表明,
person
包含一个指针,这在Rust(以及其他具有相同内存模型的语言,如C和C++)中显然是错误的。没有指针:
person
保存实际数字,
person
变量也保存实际数字。例如,您可以获取
person
的地址,将其转储,然后发现数字52存储在那里,而不是指向它的指针;让person2=Box::new(Person{…});让person3=Rc::new(Person{…})
每个
Person*
变量都包含一个指针。