【问题标题】:If C# pointers are considered "unsafe," does that mean C++ pointers are "unsafe" too?如果 C# 指针被认为是“不安全的”,那是否意味着 C++ 指针也是“不安全的”?
【发布时间】:2016-09-11 11:02:28
【问题描述】:

我正在用 C# 做一个项目,它可以从线性代数包中受益。我看过那里的那些,但我真的不想付钱,或者我发现它们不是很好。所以我决定自己写。

我读到 C++ 数组比 C# 数组快得多,但是在 C# 中使用指针数组可以获得类似的性能,尽管它们被认为是“不安全的”。我很想知道 C++ 指针有何不同,以及“不安全性”是否也适用于 C++,或者它们是否是两个根本不同的东西。

【问题讨论】:

  • “安全”是什么意思?
  • 无论您对“不安全”的定义是什么,如果它适用于 C# 指针,那么我相信它也适用于 C++ 指针。但是,C++ 没有像 C# 那样定义明确的“不安全”概念。
  • @BenjaminLindley:unsafe 是 C# 语言中的关键字。
  • @MartinBonner:是的,我明白这一点。这也是英语中的一个词,不完全清楚 OP 以什么方式使用它。
  • @MartinBonner:刚刚意识到这可能听起来很尖刻(“这也是英语中的一个词” 部分),并且不打算这样做。跨度>

标签: c# c++ arrays pointers unsafe


【解决方案1】:

C#(不安全)指针和 C++(原始)指针都具有以下特点:

  • 它们允许您引用给定地址空间中的地址。
  • 它们允许您对它们执行简单的算术运算(加法和减法),涉及整数作为偏移量。
  • 它们允许您取消引用它们指向的任何内容作为特定类型的数据。
  • 错误使用它们会引发未定义的行为,因此确保正确使用它们是您的责任。

从这个意义上说,不管有什么细微差别(如语法、固定等),C# 指针和 C++ 指针几乎是相同的编程概念。因此,它们几乎同样适用于静态分析,因此它们同样安全或不安全。因此,C# 明确将此构造称为unsafe 的事实并没有使等效的 C++ 构造“安全”。相反,使用“不安全”代码的能力在 C++ 中“始终可用”。

例如,考虑使用超出范围的索引访问数组的情况:

  • 对于 C# 数组,在使用索引器语法时会出现异常,并且在使用指针和偏移量时会调用未定义的行为。
  • 在 C++ 中使用 C 样式数组时,您将在使用索引器语法或指针和偏移量时调用未定义的行为(因为这两种语法对于 C 样式数组是等效的)。
  • 对于 C++11 std::array,在使用 array::at 时会出现异常,并且在使用索引器语法时会调用未定义的行为。

【讨论】:

  • 您的第一个项目符号需要调整,使用 dynamic 关键字或反射的代码也无法由 C# 编译器静态验证。无法完成工作的是内置在 CLR 中的验证程序。
【解决方案2】:

粗略地说(这是一个非常粗略的近似),C# unsafe 指针与 C++ 指针是同一类东西。

对于这两者,程序员有更多的责任把它做好,而对于普通的 C#,如果你弄错了,最坏的情况就是抛出异常。提供这些保证的运行时检查具有成本性能,但如果您关闭它们 - 您只能靠自己。

【讨论】:

    【解决方案3】:

    特别是,C# 中的不安全意味着可以突破托管沙箱并执行本机代码。这意味着您的托管代码可以生成非托管崩溃。这也是为什么在没有完全信任的情况下不允许使用不安全代码的原因(但您可能不再需要处理部分信任代码)。

    您可能正在考虑如何在 C# 中使用 int * 运行非托管代码。简单:故意堆栈粉碎。将其分配给堆栈上一个整数的地址,并将包含本机代码的字节数组的地址写入接下来的几个整数。

    【讨论】:

      【解决方案4】:

      unsafe 表示.Net 授予您访问您不一定分配的内存的权限。边界检查已关闭,这允许在 JIT 编译器中进行一些优化。

      通常,指针在 C++ 中是相同的,即它们授予您访问任何内存区域的权限。您可以使用运算符重载实现边界检查,但这不是指针的默认设置。

      【讨论】:

        猜你喜欢
        • 2011-10-26
        • 2018-07-29
        • 1970-01-01
        • 2012-01-27
        • 2011-06-02
        • 1970-01-01
        • 2013-08-12
        • 2012-12-17
        相关资源
        最近更新 更多