C#不安全/固定代码

时间:2008-09-17 17:12:26

标签: c# .net unsafe fixed

有人能举例说明在C#代码中实际使用“不安全”和“修复”的好时机吗?我以前玩过它,但从来没有真正找到它的好用。

考虑这段代码......

fixed (byte* pSrc = src, pDst = dst) {
    //Code that copies the bytes in a loop
}

与简单使用相比......

Array.Copy(source, target, source.Length);

第二个是.NET Framework中的代码,第一部分是从Microsoft网站http://msdn.microsoft.com/en-us/library/28k1s2k6(VS.80).aspx复制的代码。

内置的Array.Copy()比使用Unsafe代码要快得多。这可能只是因为第二个只是更好的编写,第一个只是一个例子,但你真的甚至需要使用不安全/固定代码的什么样的情况?或者,这个可怜的网络开发人员是否正在弄乱他的头脑?

7 个答案:

答案 0 :(得分:29)

对于非托管代码的互操作非常有用。传递给非托管函数的任何指针都需要修复(也就是固定)以防止垃圾收集器重新定位底层内存。

如果您正在使用P / Invoke,那么默认的编组将为您固定对象。有时需要执行自定义编组,有时需要将对象固定的时间超过单个P / Invoke调用的持续时间。

答案 1 :(得分:21)

我使用了unsafe-blocks来操作Bitmap数据。原始指针访问速度明显快于SetPixel / GetPixel。

unsafe
{
    BitmapData bmData = bm.LockBits(...)
    byte *bits = (byte*)pixels.ToPointer();
    // Do stuff with bits
}

“固定”和“不安全”通常在进行互操作时或需要额外性能时使用。 IE浏览器。 String.CopyTo()在其实现中使用unsafe和fixed。

答案 2 :(得分:8)

reinterpret_cast样式行为

如果你有点操纵,那么这可能非常有用

许多高性能哈希码实现使用UInt32作为哈希值(这使得移位更简单)。由于.Net需要Int32用于您希望快速将uint转换为int的方法。由于重要的不是实际值,只需保留值中的所有位,因此需要重新解释。

public static unsafe int UInt32ToInt32Bits(uint x)
{
    return *((int*)(void*)&x);
}

请注意,命名是在BitConverter.DoubleToInt64Bits

上建模的

继续在散列静脉中,将基于堆栈的结构转换为字节*允许轻松使用每字节散列函数:

// from the Jenkins one at a time hash function
private static unsafe void Hash(byte* data, int len, ref uint hash)
{
    for (int i = 0; i < len; i++)
    {
        hash += data[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
}

public unsafe static void HashCombine(ref uint sofar, long data)
{
    byte* dataBytes = (byte*)(void*)&data;
    AddToHash(dataBytes, sizeof(long), ref sofar);
}

不安全(从2.0开始)允许您使用stackalloc。这在需要一些小的可变长度数组(如临时空间)的高性能情况下非常有用。

所有这些用途都将坚定地存在于“只有当您的应用程序确实需要性能”时,因此在一般使用中是不合适的,但有时您确实需要它。

当你希望与一些有用的非托管函数(有很多)采用c样式数组或字符串时,需要修复

。因此,它不仅是出于性能原因,而且是在互操作场景下的正确性。

答案 3 :(得分:4)

不安全对于(例如)使用LockBits快速从图像中获取像素数据非常有用。使用托管API执行此操作的性能提升了几个数量级。

答案 4 :(得分:2)

当地址传递给旧版C DLL时,我们必须使用固定的。由于DLL在函数调用中维护了一个内部指针,如果GC压缩堆并移动了东西,所有地狱都会破坏。

答案 5 :(得分:1)

我相信如果你想访问.NET运行时以外的东西,就会使用不安全的代码。它不是托管代码(没有垃圾回收等)。这包括对Windows API和所有爵士乐的原始调用。

答案 6 :(得分:1)

这告诉我.NET框架的设计者在覆盖问题空间方面做得很好 - 确保“托管代码”环境可以完成传统(例如C ++)方法可以处理的不安全代码/指针。如果不能,如果您需要它们,那么不安全/固定功能就在那里。我敢肯定某人有一个需要不安全代码的例子,但在实践中似乎很少见 - 这是重点,不是吗? :)