C# 不安全。从字节数组到ulong数组

C# 不安全。从字节数组到ulong数组,c#,c#-7.0,C#,C# 7.0,我目前正在考虑移植my以使用C#7特性,因为有几个部分可能会从ref locals中获益以提高性能。 散列对ulong[4]数组进行计算,但结果是一个16字节数组。目前我正在将ulong数组复制到结果byte缓冲区,但这需要一些时间。 所以我想知道在这里使用System.Runtime.CompilerServices.Unsafe是否安全: var result = new byte[16]; ulong[] state = Unsafe.As<byte[], ulong[]>(r

我目前正在考虑移植my以使用C#7特性,因为有几个部分可能会从ref locals中获益以提高性能。 散列对
ulong[4]
数组进行计算,但结果是一个16
字节
数组。目前我正在将
ulong
数组复制到结果
byte
缓冲区,但这需要一些时间。 所以我想知道在这里使用
System.Runtime.CompilerServices.Unsafe
是否安全:

var result = new byte[16];
ulong[] state = Unsafe.As<byte[], ulong[]>(ref result);
ref var firstState = ref state[0];
ref var secondState = ref state[1];
ulong thirdState = 0;
ulong fourthState = 0;
var result=新字节[16];
ulong[]状态=不安全。As(参考结果);
ref var firstState=ref state[0];
ref var secondState=参考状态[1];
ulong thirdState=0;
ulong第四状态=0;
上面的代码片段意味着我将结果缓冲区也用于部分状态计算,而不仅仅用于最终输出

我的单元测试是成功的,根据benchmarkdotnet的说法,跳过块拷贝将导致20%性能提高,这足以让我了解使用它是否正确。

C#支持“固定缓冲区”,我们可以做以下几件事:

    public unsafe struct Bytes
    {
        public fixed byte bytes[16];
    }
然后

试试看。(C#中基元类型的1D数组始终存储为一个连续的内存块,这就是获取(托管)数组地址的原因)

您甚至可以返回指针以提高速度:

    public unsafe static Bytes * Convert (long[] longs)
    {
        fixed (long * longs_ptr = longs)
        return ((Bytes*)(longs_ptr));
    }
并根据需要操纵/访问字节

        var s = Convert(longs);
        var b = s->bytes[0];

你所做的似乎很好,只是要小心,因为没有什么可以阻止你这么做:

byte[] x = new byte[16];
long[] y = Unsafe.As<byte[], long[]>(ref x);

Console.WriteLine(y.Length); // still 16

for (int i = 0; i < y.Length; i++)
    Console.WriteLine(y[i]); // reads random memory from your program, could cause crash
byte[]x=新字节[16];
长[]y=不安全的As(参考x);
控制台写入线(y.长度);//还是16岁
对于(int i=0;i
在当前的.NET术语中,这非常适合
Span


请注意,
Span
获得正确的长度更改;如果您想使用SIMD进行硬件加速,那么将其转换为
Span
也很简单。

欢迎来到这里并回答好第一个问题!你正在做的是通过结构(这一个)进行转换的老“技巧”。。。如果你检查
state.Length
你会发现它是“错的”。你找到的库仍然很有趣:-)谢谢你的回答,我知道显式结构技巧,但实际上没有联系到它实际上是不安全的。as.@Tornhoof the
Unsafe.as
不需要这个技巧,但最终它还是做了同样的事情。它重新解释作为参数传递给其他类型的内容。在ILAsm中非常简单:
ldarg.0;ret
:-)没什么可做的:-)“你也可以”-不!不要那样做;一旦离开
固定的
块,指针就不可靠;实际上,它很少移动,但是:它可以(GC);切勿将指针从
固定
块向外传递(向内是可以的)关于长度问题:
Span
可以帮助解决此问题-请参阅我的answer@MarcGravell是的,这是一个更安全的选择,虽然我相信触摸速度较慢,因为长度转换等。不过,我还没有对差异进行基准测试。只要他小心一点,他也许可以在他现在做这件事的时候多找一点表现。我完全爱上了新的span/内存/不安全的东西,它让我想去重写一切。
byte[] x = new byte[16];
long[] y = Unsafe.As<byte[], long[]>(ref x);

Console.WriteLine(y.Length); // still 16

for (int i = 0; i < y.Length; i++)
    Console.WriteLine(y[i]); // reads random memory from your program, could cause crash
Span<byte> result = new byte[16];
Span<ulong> state = MemoryMarshal.Cast<byte, ulong>(result);
Span<byte> result = stackalloc byte[16];
Span<ulong> state = MemoryMarshal.Cast<byte, ulong>(result);