简体   繁体   English

C#不安全/固定代码

[英]C# Unsafe/Fixed Code

Can someone give an example of a good time to actually use "unsafe" and "fixed" in C# code? 有人可以举例说明在C#代码中实际使用“不安全”和“固定”的好时机吗? I've played with it before, but never actually found a good use for it. 我以前玩过它,但从未真正找到好的用途。

Consider this code... 考虑这段代码...

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

compared to simply using... 与仅使用...相比

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

The second is the code found in the .NET Framework, the first a part of the code copied from the Microsoft website, http://msdn.microsoft.com/en-us/library/28k1s2k6(VS.80).aspx . 第二个是.NET Framework中的代码,第一个是从Microsoft网站http://msdn.microsoft.com/zh-cn/library/28k1s2k6(VS.80).aspx复制的代码的一部分。

The built in Array.Copy() is dramatically faster than using Unsafe code. 内置的Array.Copy()比使用Unsafe代码要快得多。 This might just because the second is just better written and the first is just an example, but what kinds of situations would you really even need to use Unsafe/Fixed code for anything? 这可能只是因为第二个代码编写得更好,第一个仅仅是示例,但是您实际上需要在哪种情况下使用Unsafe / Fixed代码? Or is this poor web developer messing with something above his head? 还是这位可怜的Web开发人员搞砸了他头上的东西?

It's useful for interop with unmanaged code. 对于与非托管代码互操作很有用。 Any pointers passed to unmanaged functions need to be fixed (aka. pinned) to prevent the garbage collector from relocating the underlying memory. 传递给非托管函数的所有指针都必须固定(也称为固定),以防止垃圾回收器重新定位基础内存。

If you are using P/Invoke, then the default marshaller will pin objects for you. 如果您使用的是P / Invoke,则默认的编组器将为您固定对象。 Sometimes it's necessary to perform custom marshalling, and sometimes it's necessary to pin an object for longer than the duration of a single P/Invoke call. 有时有必要执行自定义编组,有时有必要将对象固定的时间长于单个P / Invoke调用的持续时间。

I've used unsafe-blocks to manipulate Bitmap-data. 我使用了不安全的块来操作位图数据。 Raw pointer-access is significantly faster than SetPixel/GetPixel. 原始指针访问比SetPixel / GetPixel快得多。

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

"fixed" and "unsafe" is typically used when doing interop, or when extra performance is required. 在进行互操作或需要额外性能时,通常使用“固定”和“不安全”。 Ie. 就是 String.CopyTo() uses unsafe and fixed in its implementation. String.CopyTo()在其实现中使用不安全和固定的。

reinterpret_cast style behaviour reinterpret_cast样式行为

If you are bit manipulating then this can be incredibly useful 如果您有点操纵,那么这可能会非常有用

many high performance hashcode implementations use UInt32 for the hash value (this makes the shifts simpler). 许多高性能哈希码实现使用UInt32作为哈希值(这使转换变得更简单)。 Since .Net requires Int32 for the method you want to quickly convert the uint to an int. 由于.Net需要Int32作为方法,因此您需要将uint快速转换为int。 Since it matters not what the actual value is, only that all the bits in the value are preserved a reinterpret cast is desired. 由于与实际值无关紧要,因此仅保留值中的所有位,都需要重新解释转换。

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

note that the naming is modelled on the BitConverter.DoubleToInt64Bits 请注意,命名是根据BitConverter.DoubleToInt64Bits建模的

Continuing in the hashing vein, converting a stack based struct into a byte* allows easy use of per byte hashing functions: 继续使用哈希算法,将基于堆栈的结构转换为字节*,可以轻松使用每字节哈希函数:

// 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 also (from 2.0 onwards) lets you use stackalloc. 不安全的(从2.0开始)还允许您使用stackalloc。 This can be very useful in high performance situations where some small variable length array like temporary space is needed. 这在需要某些小型可变长度数组(例如临时空间)的高性能情况下非常有用。

All of these uses would be firmly in the 'only if your application really needs the performance' and thus are inappropriate in general use, but sometimes you really do need it. 所有这些用途都将牢牢地存在于“仅当您的应用程序确实需要性能时”,因此在一般用途中不合适,但有时您确实需要它。

fixed is necessary for when you wish to interop with some useful unmanaged function (there are many) that takes c-style arrays or strings. 当您希望与使用c样式数组或字符串的一些有用的非托管函数(有很多)互操作时,fixed是必需的。 As such it is not only for performance reasons but correctness ones when in interop scenarios. 因此,在互操作方案中,这不仅是出于性能原因,而且还出于正确性的原因。

Unsafe is useful for (for example) getting pixel data out of an image quickly using LockBits. 不安全对于(例如)使用LockBits快速从图像中获取像素数据很有用。 The performance improvement over doing this using the managed API is several orders of magnitude. 使用托管API进行此操作后,性能提高了几个数量级。

We had to use a fixed when an address gets passed to a legacy C DLL. 当地址传递到旧版C DLL时,我们必须使用固定值。 Since the DLL maintained an internal pointer across function calls, all hell would break loose if the GC compacted the heap and moved stuff around. 由于DLL维护了跨函数调用的内部指针,因此,如果GC压缩了堆并四处移动了东西,所有的地狱都会崩溃。

I believe unsafe code is used if you want to access something outside of the .NET runtime, ie. 我相信,如果要访问.NET运行时之外的内容,则使用不安全的代码。 it is not managed code (no garbage collection and so on). 它不是托管代码(没有垃圾回收等)。 This includes raw calls to the Windows API and all that jazz. 这包括对Windows API和所有爵士乐的原始调用。

This tells me the designers of the .NET framework did a good job of covering the problem space--of making sure the "managed code" environment can do everything a traditional (eg C++) approach can do with its unsafe code/pointers. 这告诉我.NET框架的设计者在覆盖问题空间方面做得很好-确保“托管代码”环境可以处理传统(例如C ++)方法使用其不安全的代码/指针可以执行的所有操作。 In case it cannot, the unsafe/fixed features are there if you need them. 万一不能,如果需要,可以使用不安全/已修复的功能。 I'm sure someone has an example where unsafe code is needed, but it seems rare in practice--which is rather the point, isn't it? 我确定有人举了一个需要不安全代码的示例,但在实践中似乎很少见,这很重要,不是吗? :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM