i am new to stackoverflow and i would have a question about C# structs and their layout.
Let’s assume following structs:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct Link
{
// some primitive data (2 integers for example)
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public unsafe struct Node
{
[FieldOffset(0)]
public int LinkCount;
[FieldOffset(4)]
public Link* Links;
[FieldOffset(4)]
private fixed byte _linksData[10 * sizeof(Link)];
}
The reason for that is that i need a blittable type for IO-Performance.
I have to deal with very large (and sparse a maximum of 10 links per node) graphs which have several GB in size.
The graph is represented as an array of Node-structs.
With the setup like above i was hoping of being able to read for example a hundred MB from the graph file into a byte-pointer (which of course points to a byte-buffer) and cast it to a pointer of type Node* which yields very good performance.
At first my Node-struct just had 10 separate variables of type Link (Link0, …, Link10) which worked just fine. But it would be nice to make this configurable at compile-time, which lead to the above Node-struct.
I was hoping, that Links would just point to the same memory location as _linksData since it has the same FieldOffset.
But actually the Links pointer always is a null pointer.
So my question is:
Is there a way that Links points to the same memory location as _linksData or is there another way to have a fixed sized array of structs embedded into another struct.
Thanks for every answer in advance – Markus
After reading Ben Voigt’s post I tryed something similar without the need of changing the struct to a class. The following is how it works for me:
[StructLayout(LayoutKind.Explicit, Pack = 1)]
public unsafe struct Node
{
[FieldOffset(0)]
public int LinkCount;
[FieldOffset(4)]
private fixed byte _linksData[10 * sizeof(Link)];
public Link* GetLinks()
{
fixed(byte* pLinksData = _linksData)
{
return (Link*)pLinksData;
}
}
}
I guess that you’re not actually trying to store a pointer, just have a correctly-typed way to access the 10 elements. How about:
No, wait, .NET supports interior pointers but C# doesn’t, so that won’t work. You can only have a pointer into a .NET object if you’ve pinned it or placed it on the stack, and we don’t know if that’s the case here.
🙁
Full-on wrapper time:
Note that I had to change
Nodeto a class… p/invoke should still act pretty much the same though.If you don’t want to do that, extension methods might be an answer.