5

在这里,我正在尝试使用 C# 的不安全功能:http: //ideone.com/L9uwZ5

我知道,C# 中的这种方式是最糟糕的,我想承认,该主题中有一些信息。看“变态”这个词。

我想在 C# 中实现快速排序,比如纯 C 方式(甚至不是 C++)。这可能很疯狂,但只是想深入了解不安全的 C# 的可能性。

我一直在尝试使用stackalloc运算符。我知道,这是从堆栈分配,而不是从堆分配,这就是我执行程序失败的原因。

但是当我在这个程序中没有看到任何异常/错误时,我感到很困惑。

  • 为什么我没有得到任何明确的异常/错误?

此外,正如您看到的代码的注释部分:

struct Header
{
    internal int* data;
};

Header* object_header = stackalloc Header[sizeof(Header)];
object_header->data = stackalloc int[length];

我不能用最后一行编译它。C# 编译器告诉我们,在这个表达式中不能使用stackalloc 。为什么?data 是int *类型,为什么这里会出现错误呢?

我只想使用堆栈框架而不是使用堆。我知道,还有另一种方法,但它是从堆中分配的。

int*[] data = new int*[length * sizeof(int)];
IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(length * sizeof(int)));
Marshal.WriteInt32(result, 0);
for(int i = 0; i < length * sizeof(int); i++) d[i] = (int*)result;

例如,但这不是堆栈分配。

我怎样才能解决我的变态任务,明确地使用 C# 语言中的堆栈分配和纯 C 样式语法。

C# 不是为这样的目标而创建的,这样的特性很愚蠢——我知道,但主要问题不是关于重要性,而是关于这些特性。

4

2 回答 2

5

Marc 展示了解决方法,我将尝试解释为什么需要这样做。实际上,您正在编写非托管代码,但该方法在很大程度上仍然是一种托管方法。它从 IL 编译成机器代码,垃圾收集器将在其堆栈帧和 cpu 寄存器中搜索对象引用。

编译方法时,抖动执行两个重要任务。一个是显而易见且高度可见的,将 IL 转换为机器代码。但是还有另一个非常重要的任务,它是完全不可见的,它为方法生成元数据。显示堆栈帧的哪些部分包含对象引用以及哪些部分存储指针和值类型值的表。并且在代码中的哪个点,cpu 寄存器将存储对象引用。此外,在方法代码中的什么时候对象引用超出范围。GC.KeepAlive() 的原因,这是一个非常独特的方法,根本不生成任何代码。

垃圾收集器需要该表来可靠地找到对象引用。然而,该表只有一个间接级别。它可以描述为object_header分配的堆栈空间,并将指针和指向的堆栈区域标记为“不扫描对象引用”。当您直接分配object_header->data时,它无法描述堆栈空间的块。它没有额外的间接将堆栈细分为更小的部分并描述标题。使用虚拟局部变量解决了这个问题。

于 2012-11-26T15:20:26.333 回答
3
于 2012-11-26T12:38:24.773 回答