我正在制作一个类似于SafeBuffer
针对 .NET 2.0 的类。其中一个功能是void ReadArray<T>(long position, T[] array, int offset, int count)
(or WriteArray
),它将一系列 (blittable) 结构读入/写入数组。
我的第一个猜测是简单地使用Marshal.PtrToStructure
/StructureToPtr
和推进 by Marshal.SizeOf
。然而,查看 IL 以获取SafeBuffer.ReadArray
它Marshal.AlignedSizeOf<T>()
用于提升的节目(一种内部方法)。该函数定义为:
uint s = Marshal.SizeOf<T>();
if (s == 1u || s == 2u || IntPtr.Size == 8 && s == 4u) { return s; }
return Marshal.AlignedSizeOfType(typeof(T)); // an internalcall
该方法仅在 .NET 4.0 中定义,因此我无法使用(也无法在 Rotor 中使用)。
我的想法是Marshal.UnsafeAddrOfPinnedArrayElement
在数组中的相邻元素上使用,但这不起作用。这是我的测试代码:
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace test
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
struct A
{
byte a;
short x;
byte b;
}
private static MethodInfo MarshalAlignedSizeOf;
static int MAlignedSizeOf(Type t)
{
if (MarshalAlignedSizeOf == null) { MarshalAlignedSizeOf = typeof(Marshal).GetMethod("AlignedSizeOf", BindingFlags.NonPublic | BindingFlags.Static); }
return (int)(uint)MarshalAlignedSizeOf.MakeGenericMethod(t).Invoke(null, null);
}
static int AlignedSizeOf(Type t)
{
Array a = Array.CreateInstance(t, 0);
GCHandle pin = GCHandle.Alloc(a, GCHandleType.Pinned);
try
{
return (int)(Marshal.UnsafeAddrOfPinnedArrayElement(a, 1).ToInt64() - Marshal.UnsafeAddrOfPinnedArrayElement(a, 0).ToInt64());
}
finally { pin.Free(); }
}
unsafe static void Main(string[] args)
{
Console.WriteLine("sizeof: " + sizeof(A));
Console.WriteLine("SizeOf: " + Marshal.SizeOf(typeof(A)));
Console.WriteLine("aligned size: " + AlignedSizeOf(typeof(A)));
Console.WriteLine("mars algn sz: " + MAlignedSizeOf(typeof(A)));
}
}
}
x86 或 x64 上的哪些输出6, 6, 6,
8
(请注意本机 AlignedSizeOf 有何不同?)。
所以问题是:
- 讨论:为什么这个对齐大小与正常大小不同?在 C/C++ 中 sizeof() 是完全对齐的值。(
sizeof(arr)/sizeof(arr[0])
总是有效) - 是否有一种托管方式(有或没有不安全代码)来获得 blittable 通用结构的对齐大小?
- 我应该只使用
SizeOf()
而不关心这个额外的对齐吗?在那种情况下,我可能只是在进行块转移......