views:

2935

answers:

7

Can someone give an example of a good time to actually use "unsafe" and "fixed" in C# code? 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.

The built in Array.Copy() is dramatically faster than using Unsafe code. 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? Or is this poor web developer messing with something above his head?

+1  A: 

I believe unsafe code is used if you want to access something outside of the .NET runtime, ie. it is not managed code (no garbage collection and so on). This includes raw calls to the Windows API and all that jazz.

matwilko
"Unsafe" does not mean "Unmanaged". Unsafe methods in C# are managed methods that are allowed to manipulate pointers. The code, however, is still managed.If you want to use unmanaged (native) code in your application, you can use C++/CLI and its #pragma directives.
SealedSun
A: 

We had to use a fixed when an address gets passed to a legacy 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.

Nick
A: 

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 (e.g. C++) approach can do with its unsafe code/pointers. 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? :)

Patrick Szalapski
+1  A: 

Unsafe is useful for (for example) getting pixel data out of an image quickly using LockBits. The performance improvement over doing this using the managed API is several orders of magnitude.

Nick
+7  A: 

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. 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.

Brannon
+3  A: 

I've used unsafe-blocks to manipulate Bitmap-data. Raw pointer-access is significantly faster than 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.

Rune
I would change "significantly" to "many orders of magnitude". It's unbelievable how slow SetPixel and GetPixel are. Pixel access was faster on an Apple IIe in 1980.
MusiGenesis
+5  A: 

reinterpret_cast style behaviour

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). Since .Net requires Int32 for the method you want to quickly convert the uint to an 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

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. 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. As such it is not only for performance reasons but correctness ones when in interop scenarios.

ShuggyCoUk