安全代码中的不安全标记

时间:2014-02-03 11:16:01

标签: c# unsafe

我正在帮助的项目中有一个人在性能重要代码中随处放置unsafe标记,无论是否需要。通常这个标签可以安全地移除,但不幸的是,很难证明他,他不应该这样做。任何人都可以给我一篇好的权威文章,这证明了我或他的观点,所以我们终于可以解决这个问题吗?

他使用unsafe的代码示例:

            unsafe
            {
                writeableBmp.CopyPixels(new Int32Rect(1, 0, (int)(width - 1), (int)height - 1), buffer, writeableBmp.BackBufferStride, 0);
                writeableBmp.Lock();
                writeableBmp.WritePixels(new Int32Rect(0, 0, (int)width - 1, (int)height - 1), buffer, writeableBmp.BackBufferStride, 0, 0);
                writeableBmp.AddDirtyRect(new Int32Rect(0, 0, (int)width - 1, (int)height - 1));
                writeableBmp.Unlock();
            }

他的观点是他读到了需要unsafe的地方,并通过给编译器提示提高了性能,代码片应该以不同方式编译。

2 个答案:

答案 0 :(得分:3)

根据http://msdn.microsoft.com/en-us/library/t2yzs44b.aspx,不安全只会创建一个不安全的上下文。只有在使用被认为不安全的指针算法等时才需要这样做,因此需要创建不安全的上下文。

在任何其他情况下,它都没有任何好处,因为它不会禁用任何东西。

使用和不使用它来配置代码或检查MSIL以证明它。

只需删除它,如果有不安全的代码,编译器会告诉你。

一些方法:

using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace CSharpTestbench
{
    class Program
    {
        static void Main(string[] args)
        {

            int x = 42;
            if (x == 42)
            {
                Console.WriteLine("it is 42");
            }
        }
    }
}

以这种方式查找非优化的MSIL代码:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       30 (0x1e)
  .maxstack  2
  .locals init ([0] int32 x,
           [1] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   42
  IL_0003:  stloc.0
  IL_0004:  ldloc.0
  IL_0005:  ldc.i4.s   42
  IL_0007:  ceq
  IL_0009:  ldc.i4.0
  IL_000a:  ceq
  IL_000c:  stloc.1
  IL_000d:  ldloc.1
  IL_000e:  brtrue.s   IL_001d
  IL_0010:  nop
  IL_0011:  ldstr      "it is 42"
  IL_0016:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001b:  nop
  IL_001c:  nop
  IL_001d:  ret
} // end of method Program::Main

用不安全的结果装饰它:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       32 (0x20)
  .maxstack  2
  .locals init ([0] int32 x,
           [1] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ldc.i4.s   42
  IL_0004:  stloc.0
  IL_0005:  ldloc.0
  IL_0006:  ldc.i4.s   42
  IL_0008:  ceq
  IL_000a:  ldc.i4.0
  IL_000b:  ceq
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  brtrue.s   IL_001e
  IL_0011:  nop
  IL_0012:  ldstr      "it is 42"
  IL_0017:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001c:  nop
  IL_001d:  nop
  IL_001e:  nop
  IL_001f:  ret
} // end of method Program::Main

当然,两者都编译为/不安全。 实际上,不安全的代码有更多的指令,它们会产生稍微大一点的可执行文件,但应该可以忽略不计。不安全的调用只是被NOP CIL指令取代,这些指令实际上“什么都不做”,期望增加可执行文件的大小(http://en.wikipedia.org/wiki/List_of_CIL_instructions)。

它增加了缩进并使代码更难阅读,因为它还意味着存在不安全的代码。

R#也说没必要。

开发人员有什么证据支持这种说法?

答案 1 :(得分:3)

以下是您的链接:http://en.wikipedia.org/wiki/Premature_optimization#When_to_optimize

除了他在假设不安全方面完全错误使代码更快的原因之外,使用随机关键字可能影响性能并不是任何专业人员开发代码的方式。

首先,编写代码,在性能和代码复杂性之间取得良好的平衡 - 即,如果您可以编写运行速度更快的更干净的编码器,那就去做吧。如果你能编写运行得更快的更脏的代码,那就不要了。 其次,弄清楚性能是否足够。如果是的话,你就完成了。如果不是,请确定哪个部分最能影响您的表现,修复那部分,然后单独留下其他部分。

回到不安全状态:不安全并不快。如果您知道如何执行此操作,它允许您编写速度更快,安全性更低(a.k.a.不安全)的代码,允许您编译否则将无法编译的代码。但是,对普通代码进行不安全处理并不会产生任何积极的性能差异。

不幸的是,对你来说,你的同事是如此遥远,以至于很难找到专门针对这个问题的文章“默认情况下,安全代码更快”。因为默认情况下不安全的代码更快,任何地方既没有陈述也没有暗示,举证责任应该在他身上。但是,如果没有任何有能力的前辈或经理,可能很难说服他就是这种情况。所以我能看到的最好的攻击点就是过早的优化 - 如果他的代码更复杂,他就必须证明它。