安全代码与不安全代码

11

今天阅读了关于安全和不安全代码的这个问题,然后在MSDN上阅读了相关内容,但我仍然不理解。为什么要在C#中使用指针?这纯粹是为了速度吗?


15
如果你是一个明智的人,那么你永远不会“想要”在C#中使用指针。它们存在于那些无论你是否“想要”,都必须在C#中使用指针的情况下。 :-) - Eric Lippert
4个回答

25

使用不安全代码的原因有三个:

  • API (正如John所指出)
  • 获取数据的实际内存地址 (例如访问内存映射硬件)
  • 访问和修改数据的最高效方式 (时间关键性能要求)

6
对于时间敏感的应用程序来说,使用.NET本身并不明智。垃圾回收器是不确定性的,可能会在任何时刻触发。这基本上会破坏你的时间敏感应用程序。 顺便提一下,我同意其他观点! - Henri
2
我听到过使用不安全的C#的另一个原因是确保安全敏感信息(例如密码或私有加密密钥)在确定性时间点从内存中删除。否则,密码可能会一直停留在内存中,直到其他人想要写入相同的位置。 - harms

5
有时候,你需要指针来将C#与底层操作系统或其他本地代码接口化。强烈不建议这样做,因为它是“不安全的”(自然而然)。
只有在极少数情况下,你的性能如此CPU绑定,以至于你需要那微小额外的性能。我的建议是,在汇编或C / C ++中编写这些CPU密集型模块的单独模块,导出API,并让你的.NET代码调用该API。一个可能的附加好处是,你可以将平台特定的代码放在未管理的模块中,并使.NET平台无关。

1
为什么你建议在处理性能敏感的代码时切换编程语言?其优势并不是很清晰。为什么不使用C#语言的全部特性呢? - Jeffrey L Whitledge
选择正确的工具做正确的事?如果我要处理指针和其他低级别的工作,我宁愿使用C/C++,因为我有很多可用的工具。在C#中不支持内联汇编、基于指针和其他位操作等有用的功能。 - John Källén
我同意,在编写汇编或C代码时,您需要关注您的代码是如何编译的。 - ChaosPandion
当从C#到C进行编组和反编组时,使用汇编或优化代码获得的性能大部分都会消失。 - Henri
3
即使使用不安全的C#,您仍然在托管环境中工作。 JIT可以针对正确的CPU进行优化,并在适当时执行其他优化(如内联方法)。如果您不需要另一种语言的额外功能,并且已经在使用C#编写代码,并且想要进行指针操作以提高性能,则我认为“unsafe” C#是正确的选择。 - Jeffrey L Whitledge
1
我同意你的观点,如果你只是在内存块上跳舞而没有调用特定于平台的功能,那么在C#的范围内保持合理可能是合理的。@Henri:你应该尽量确保你的非托管API足够细粒度,这样你就不需要在紧密循环中调用它,否则会影响性能。就像你不会通过调用SetPixel() width * height次来绘制位图,而是调用BitBlt一样。 - John Källén

4

我通常不使用它,但有时它非常有用:

  • 用于处理原始缓冲区(图形等)的性能
  • 某些非托管API所需(对于我来说也非常罕见)
  • 为了欺骗数据

例如,在我维护的一些序列化代码中,将一个float写入流而无需使用BitConverter.GetBytes(每次都创建一个数组)是很痛苦的 - 但我可以欺骗:

float f = ...;
int i = *(int*)&f;

现在我可以使用 shift (>>) 等符号更轻松地编写 i,而不是编写 f(字节将与调用 BitConverter.GetBytes 相同,并且现在我通过选择如何使用 shift 来控制字节序)。


3
我理解你为什么这样做,但那段C#代码让我感到不舒服。 - Stephan
我看到这个(代码)时不禁笑了出来:for cheating with data。你真逗啊我的朋友!虽然我从没试过,但这个例子确实说得通! - Mike Perrenoud

0

至少有一个托管的 .Net API 经常使使用指针不可避免。请参见 SecureStringMarshal.SecureStringToGlobalAllocUnicode

获取 SecureString 的明文值的唯一方法是使用其中一个 Marshal 方法将其复制到非托管内存中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接