I have defined a struct in C# to mirror a native data structure and used the StructLayout of Sequential. To transform the struct to the 12 bytes (3x 4 bytes) required by the Socket IOControl method, I am using Marshal.Copy to copy the bytes to an array.
As the struct only contains value types, do I need to pin the structure before I perform the copy? I know the GC compacts the heap and therefore the mem address of reference types can change during a GC. Is the same the case for stack allocated value types?
The current version which includes the pin operation looks like:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct TcpKeepAliveConfiguration
{
public uint DoUseTcpKeepAlives;
public uint IdleTimeMilliseconds;
public uint KeepAlivePacketInterval;
public byte[] ToByteArray()
{
byte[] bytes = new byte[Marshal.SizeOf(typeof(TcpKeepAliveConfiguration))];
GCHandle pinStructure = GCHandle.Alloc(this, GCHandleType.Pinned);
try
{
Marshal.Copy(pinStructure.AddrOfPinnedObject(), bytes, 0, bytes.Length);
return bytes;
}
finally
{
pinStructure.Free();
}
}
}
Any thoughts?
If your structure is captured by, say, a lambda expression, it won't be stored on the stack.
Thus, I'd recommend you always pin the structure before copying.
Eric Lippert wrote an article about value type storage that might interest you.
Frédéric and Aliostad are correct; you do not know where the "this" actually lives, and therefore you don't know whether the garbage collector is allowed to move it or not.
I just want to point out that there is an equivalent solution to your problem that you might find useful. You can also solve your problem with:
public byte[] ToByteArray()
{
byte[] bytes = new byte[Marshal.SizeOf(typeof(TcpKeepAliveConfiguration))];
unsafe
{
fixed (TcpKeepAliveConfiguration* ptr = &this)
{
// now you have pinned "this" and obtained a pointer to it in one step
}
}
}
The "fixed" statement ensures that during the body of its block, the unmanaged pointer to "this" is valid because the memory cannot be moved by the garbage collector. Basically it is another way of writing your code; some people find this way a bit easier to read.
(Note that you have to check the "allow unsafe" checkbox in Visual Studio or use the "/unsafe" flag on the command line when you are building code that contains an unsafe context.)
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