views:

139

answers:

4

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

I made a struct 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
}

Total size of the struct must be 20 bytes.

When I do a sizeof() of this struct:

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?

+2  A: 

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

LaZe
no, object in .net (except for primitives like int) have size more than sum of fields.
Andrey
+5  A: 

Actually technically the strut must be a MINIMUM of 20 bytes - if you allocate more when sending, the receiver just wont use / copy them. The problem is always underallocation.

That said, I I see the problem. Hm. I think the problem is the last long.... which IMHO gets aligned to 8 bytes, injecting 4 empty bytes before. I think there is a performane penalty for hainvg an 8 byte element not aligned to an 8 byte boundary.

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

Reference: http://support.microsoft.com/kb/922785

[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 1 byte boundary. You can go furthe by defining the exact start of every element, too, if needed.

TomTom
Your solution works too. Thank you very much. Your solution seems to be easier than John's answer. I will use your solution.. Bye
+6  A: 

As a general rule, CPU's like to have variables aligned in memory at location that is an even multiple of their size, so a 4 byte int should be on a memory address that is divisible by 4, and an 8 byte long should be at an address divisible by 8.

The C# (and C++) language designers know this and they will insert padding in structures to provide the necessary alignement. 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 structs to align properly (rather than packing them) if you can.

John Knoeller
You have complety right ! Thank you very much
Wow, I love this type of feedback. I just learned something new and interesting.
Nissan Fan
+1  A: 

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;
}
Kevin McKelvin