Skip to content

Instantly share code, notes, and snippets.

@xoofx
Created June 1, 2016 21:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save xoofx/111663e43a035ac109973eff53fd6f08 to your computer and use it in GitHub Desktop.
Save xoofx/111663e43a035ac109973eff53fd6f08 to your computer and use it in GitHub Desktop.
Cast an array of blittable structs to an array of byte[], transform length as well
using System;
using System.Runtime.InteropServices;
namespace EvilArray
{
/// <summary>
/// Cast an array of structs to an array of byte[]
/// </summary>
class Program
{
/// <summary>
/// A blittable struct
/// </summary>
struct Vector3
{
public Vector3(byte x, byte y, byte z)
{
X = x;
Y = y;
Z = z;
}
// We use byte here just to be able to read easily and verify the values
// But we could use floats
public byte X;
public byte Y;
public byte Z;
}
// Allow to cast a Vector3[] to byte[]
[StructLayout(LayoutKind.Explicit)]
struct AliasArray
{
[FieldOffset(0)]
public Vector3[] Array;
[FieldOffset(0)]
public byte[] AsByteArray;
}
/// <summary>
/// Transform an array of Vector3[] to an array of byte[]. Transform length
/// </summary>
/// <param name="array">The array.</param>
/// <returns>The equivalent byte array</returns>
static unsafe byte[] Alias(Vector3[] array)
{
// Create a new array
var patch = new AliasArray
{
Array = array
};
// Get the length
fixed (void* pArray = patch.Array)
{
// Patch the Type ptr
fixed (void* pByte = new byte[1])
{
var arrayBytePType = *(void**)((byte*)pByte - 4 - IntPtr.Size);
*(void**)((byte*)pArray - 4 - IntPtr.Size) = arrayBytePType;
}
// Patch the length
*((int*)pArray - 1) = patch.Array.Length * sizeof(Vector3);
}
return patch.AsByteArray;
}
// Patch the Vector3[] to a byte[]
static void Main(string[] args)
{
// Create a new array
var byteArray = Alias(new[]
{
new Vector3(0, 1, 2),
new Vector3(3, 4, 5),
}
);
for (int i = 0; i < byteArray.Length; i++)
{
Console.WriteLine(byteArray[i]);
}
}
}
}
@superlloyd
Copy link

Very interesting!!
While I can make a guess reading the code, it would be nice to to have the function to do the reverse transformation.
As a side note I tried to extend this sample with generic type "T" (where T: struct), but the compiler refuse to compile this code for generic! :'(
I guess it's a good use for T4 templates....

@jkotas
Copy link

jkotas commented Jun 10, 2016

These tricks will result into crashes - when the GC kicks in at the wrong moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment