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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With