Size of structures in .NET

谁说我不能喝 提交于 2020-01-12 07:16:28

问题


My problem is to send a structure between a program in C to a C# program.

I made a structure in C#:

public struct NetPoint {
    public float lat; // 4 bytes
    public float lon; // 4 bytes
    public int alt; // 4 bytes
    public long time; // 8 bytes
}

The total size of the structure must be 20 bytes.

When I do a sizeof() in C++ of this structure,

System.Diagnostics.Debug.WriteLine(
    "SizeOf(NetPoint) = " +
    System.Runtime.InteropServices.Marshal.SizeOf(new NetPoint()));

the debug console shows:

SizeOf(NetPoint) = 24

But I expected to have 20 bytes. Why do I see a difference?


回答1:


Actually, technically the structure must be a minimum of 20 bytes. If you allocate more when sending, the receiver just won't use / copy them. The problem is always underallocation.

That said, I see the problem. Hmm. I think the problem is the last long.... which IMHO gets aligned to eight bytes, injecting four empty bytes before. I think there is a performance penalty for having an eight-byte element not aligned to an eight-byte boundary.

Attach StructLayout attributes to determine the offset of every element manually. Then you should be able to get things in line.

Reference: How to control the physical layout of the data fields in the .NET Framework 2.0

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct NetPoint {  
    public float lat; // 4 bytes 
    public float lon; // 4 bytes 
    public int alt; // 4 bytes 
    public long time; // 8 bytes 
} 

That at least should align elements to a one-byte boundary. You can go further by defining the exact start of every element, too, if needed.




回答2:


As a general rule, CPUs like to have variables aligned in memory at a location that is an even multiple of their size, so a four-byte integer should be on a memory address that is divisible by four, and an eight-byte long should be at an address divisible by eight.

The C# (and C++) language designers know this, and they will insert padding in structures to provide the necessary alignment. So the actual layout of your structure looks like this:

public struct NetPoint {
    public float lat;          // 4 bytes   Offset  0
    public float lon;          // 4 bytes   Offset  4
    public int alt;            // 4 bytes   Offset  8
    int to_preserve_alignment; // 4 bytes   Offset 12
    public long time;          // 8 bytes   Offset 16
}

You can fix this by making the long the first value, as a rule, if you always put the largest values at the beginning of your structures, you won't have any padding inserted to preserve alignment of members.

You can also fix it by adding

[StructLayout(LayoutKind.Sequential, Pack = 4)]

before the structure declaration, but that will result in mis-aligned long time which hurts performance. On some CPUs it hurts performance quite a lot. (The ALPHA AXP would fault on misaligned members, for instance). x86 CPUs have only a minor performance penalty, but there is a danger of future CPUs having a major performance penalty, so it's best to design your structures to align properly (rather than packing them) if you can.




回答3:


Try adding the attribute [StructLayout(LayoutKind.Sequential, Pack = 1)] and see what happens. I suspect an 8 byte padding, so it's 3x8 bytes.




回答4:


TomTom answered this question pretty well I think, but there is another alternative if you end up in a tricky COM interop struct situation. Each field can be aligned on its own using FieldOffset attributes.

[StructLayout(LayoutKind.Explicit)]
public struct COMPoint
{
    [FieldOffset(0)] public int X;
    [FieldOffset(4)] public int Y;
}


来源:https://stackoverflow.com/questions/2428168/size-of-structures-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!