33

有人可以举例说明在 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 代码快得多。这可能只是因为第二个写得更好,第一个只是一个例子,但是你真的需要在什么情况下使用不安全/固定代码?还是这个可怜的 Web 开发人员在搞乱他头上的东西?

4

7 回答 7

31

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

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

于 2008-09-17T17:22:49.087 回答
24

我使用不安全块来操作位图数据。原始指针访问比 SetPixel/GetPixel 快得多。

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

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

于 2008-09-17T17:46:57.373 回答
8

reinterpret_cast 风格行为

如果您有点操纵,那么这将非常有用

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

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

请注意,命名是基于BitConverter.DoubleToInt64Bits

继续散列,将基于堆栈的结构转换为 byte* 可以轻松使用每字节散列函数:

// 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);
}

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

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

当您希望与采用 c 样式数组或字符串的一些有用的非托管函数(有很多)进行互操作时,fixed 是必需的。因此,这不仅是出于性能原因,也是出于互操作场景中的正确性原因。

于 2009-01-28T16:05:27.393 回答
4

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

于 2008-09-17T17:22:20.303 回答
3

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

于 2008-09-17T17:20:06.190 回答
1

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

于 2008-09-17T17:17:32.843 回答
1

这告诉我,.NET 框架的设计者在解决问题方面做得很好——确保“托管代码”环境可以完成传统(例如 C++)方法可以通过其不安全的代码/指针完成的所有事情。万一它不能,如果你需要它们,不安全/固定的功能就在那里。我敢肯定有人有一个需要不安全代码的例子,但在实践中似乎很少见——这才是重点,不是吗?:)

于 2008-09-17T17:20:47.123 回答