Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Size of structures in .NET

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?

like image 270
user291830 Avatar asked Mar 11 '10 19:03

user291830


2 Answers

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.

like image 68
John Knoeller Avatar answered Oct 13 '22 21:10

John Knoeller


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.

like image 7
TomTom Avatar answered Oct 13 '22 23:10

TomTom