unsafe static void SquarePtrParam (int* p)
{
*p *= *p;
}
VS
static void SquarePtrParam (ref int p)
{
p *= p;
}
安全代码可以在任何可以运行C#代码的情况下运行(Silverlight、共享托管ASP.NET、XNA、SQL Server等),而不安全的代码需要提升信任级别。这意味着您可以在更多地方运行代码,并受到更少的限制。
此外,它是安全的,这意味着您不必担心做错事情并崩溃您的进程。
String
和 BitConverter
等类中广泛使用了 fixed
指针,因此我想代价不会太高。 - Gabefixed
部分可能只是元数据,由 GC 使用。JITter 可以存储信息,即代码中某个寄存器中的值指向一个无法重新定位的对象。因此,使用 fixed
可能会增加额外的元数据开销和 GC 的额外工作量,但在执行时不会消耗 CPU 周期。 - Gabefixed
关键字实际上并不会固定一个对象。它只是创建了另一个指针,这个指针对垃圾回收器可见。非常高效。 - Hans Passant使用不安全的代码只有一个原因:原始性能。
使用不安全的代码,您可以像使用C++指针一样使用它,而运行时几乎没有太多检查。没有检查意味着您需要自己负责,但开销较小。
我只看到过它用于加速图像/位图处理。但您也可以将其用于内联字符串操作(是的,使字符串可变!!!无论如何都是个坏主意,除非您想构建StringBuilder)。其他用途包括矩阵计算或其他重型数学运算。还可能涉及与操作系统的接口和一些黑客技术。
using System;
using System.Diagnostics;
public static class Program {
private const Int32 c_numElements = 10000;
public static void Main() {
const Int32 testCount = 10;
Stopwatch sw;
// Declare a two-dimensional array
Int32[,] a2Dim = new Int32[c_numElements, c_numElements];
// Declare a two-dimensional array as a jagged array (a vector of vectors)
Int32[][] aJagged = new Int32[c_numElements][];
for (Int32 x = 0; x < c_numElements; x++)
aJagged[x] = new Int32[c_numElements];
// 1: Access all elements of the array using the usual, safe technique
sw = Stopwatch.StartNew();
for (Int32 test = 0; test < testCount; test++)
Safe2DimArrayAccess(a2Dim);
Console.WriteLine("{0}: Safe2DimArrayAccess", sw.Elapsed);
// 2: Access all elements of the array using the jagged array technique
sw = Stopwatch.StartNew();
for (Int32 test = 0; test < testCount; test++)
SafeJaggedArrayAccess(aJagged);
Console.WriteLine("{0}: SafeJaggedArrayAccess", sw.Elapsed);
// 3: Access all elements of the array using the unsafe technique
sw = Stopwatch.StartNew();
for (Int32 test = 0; test < testCount; test++)
Unsafe2DimArrayAccess(a2Dim);
Console.WriteLine("{0}: Unsafe2DimArrayAccess", sw.Elapsed);
Console.ReadLine();
}
private static Int32 Safe2DimArrayAccess(Int32[,] a) {
Int32 sum = 0;
for (Int32 x = 0; x < c_numElements; x++) {
for (Int32 y = 0; y < c_numElements; y++) {
sum += a[x, y];
}
}
return sum;
}
private static Int32 SafeJaggedArrayAccess(Int32[][] a) {
Int32 sum = 0;
for (Int32 x = 0; x < c_numElements; x++) {
for (Int32 y = 0; y < c_numElements; y++) {
sum += a[x][y];
}
}
return sum;
}
private static unsafe Int32 Unsafe2DimArrayAccess(Int32[,] a) {
Int32 sum = 0;
fixed (Int32* pi = a) {
for (Int32 x = 0; x < c_numElements; x++) {
Int32 baseOfDim = x * c_numElements;
for (Int32 y = 0; y < c_numElements; y++) {
sum += pi[baseOfDim + y];
}
}
}
return sum;
}
}
Unsafe2DimArrayAccess方法标记为不安全,需要使用C#的fixed语句。要编译此代码,您需要在调用C#编译器时指定/unsafe开关或在Microsoft Visual Studio的项目属性窗格的“生成”选项卡上选中“允许不安全代码”复选框。 当我在我的机器上运行此程序时,我得到以下输出:
00:00:02.0017692: Safe2DimArrayAccess
00:00:01.5197844: SafeJaggedArrayAccess
00:00:01.7343436: Unsafe2DimArrayAccess
从上面可以看出,安全的二维数组访问技术是最慢的。安全的交错数组访问技术比安全的二维数组访问技术快一点。但是需要注意的是,创建交错数组比创建多维数组更耗时,因为创建交错数组需要在堆上为每个维度分配一个对象,这会导致垃圾收集器周期性地启动。所以存在一个权衡:如果您需要创建大量“多维数组”,并且打算不经常访问元素,则创建多维数组更快。如果您只需要创建“多维数组”一次,并且经常访问其元素,则交错数组将提供更好的性能。当然,在大多数应用程序中,后一种情况更为常见。
我认为在你给出的例子中使用不安全代码并没有优势。我只有在需要与非托管代码交互时才会真正使用不安全代码,例如调用非组件 DLL 接口。
ref
或out
而不是指针。 - P Daddy