问题描述
我试图了解如何将结构体作为结构体的成员存储在内存中。据我了解,如果我们在内存中有一个简单的结构,例如
struct Simple {
int x;
bool y;
}
然后,如果我们在内存中初始化 Simple s = new Simple()
,我们会看到类似
s(0x01) --> 0x01(x - 32 bits data,y - 32 bits data)
因此,如果我们调用 s.x
,那么我们需要将 s
提取到 cpu 中,然后才能访问 x 和 y 进行操作,因为它们是连续的。
现在如果我们有一个结构数组作为成员
struct Simple {
int x;
Other[] otherArray;
Simple(int input,Other[] otherInput)
{
x = input;
otherArray = otherInput;
}
}
struct Other {
bool y;
}
如果我们做了 Simple s = new Simple()
那么在内存中我们就会有
s(0x01) --> 0x01(x - 32 bits,otherArray - 64 bit reference type)
s.otherArray[0]
需要单独获取存储在内存中的任何位置。这是因为 otherArray
中的实际值没有与 x
连续存储,但对数据的引用在 x
之后是连续的。如果 otherArray
被初始化为 Simple s = new Simple(1,new Simple[1])
,那么 otherArray
数据是在 x 之后连续存储还是 otherArray
总是将是一个引用类型(无论它是在结构中初始化构造函数与否)?
最后,如果我们有一个结构体作为结构体的成员
struct Simple {
int x;
Other other;
}
这是我不清楚的地方。 Simple s = new Simple()
现在存储为
s(0x01) --> 0x01(x - 32 bits data,other - 32 bits data of y as bool)
或者是
s(0x01) --> 0x01(x - 32 bits,other - some reference to the data containing y as bool)
换句话说,作为结构体成员的结构体是与结构体连续存储还是简单地存储为其他结构体的实际数据的某种地址?
我也希望能对我的逻辑进行任何更正或进一步了解不同类型如何存储在 struct 中的内存中,因为我试图大致了解 C# 如何在内存中存储数据,谢谢
解决方法
otherArray
数据会在 x
之后连续存储还是 otherArray
始终是引用类型
otherArray
始终是对数组对象的引用,即使它只有一个元素。结构体布局是结构体类型的属性,而不是特定结构体值的属性。
一个结构体是作为结构体的成员与结构体连续存储还是简单地存储为其他结构体的实际数据的某种地址?
结构是值类型,因此没有“其他结构实际数据的某种地址”。这就是引用类型的作用。它不一定是连续的,(但在 Other
和 Simple
的情况下它是连续的)-如果您没有指定明确的 Pack
或 {{,它将遵循默认对齐规则1}}。有关详细信息,请参阅 here。
让我们考虑:
LayoutKind
和价值:
struct Simple
{
public int x;
public Other other;
}
struct Other
{
public int y;
}
您希望 var s = new Simple();
s.x = unchecked((int)0xabcdefab);
s.other.y = 0x12345678;
的大小为 8 个字节,其值将包含数字 s
和 0xabcdefab
:
0x12345678
您可以尝试向 // prints 8
Console.WriteLine(sizeof(Simple));
// in an unsafe block,prints 12345678ABCDEFAB
Console.WriteLine(Marshal.ReadInt64(new IntPtr(&s)).ToString("X"));
添加更多字段,并看到 Other
增加
将此与引用类型进行比较:
sizeof(Simple)
您现在不能使用 struct Simple
{
public int x;
public OtherRef other;
}
class OtherRef
{
public int y;
}
来获取地址,所以这里有一个 sharplab 链接来表明 &
字段确实是一个地址,而不是您设置的值.