我正在用 C# 编写一些不安全的代码(跟进 this question )并且我想知道,为什么 stackalloc
确实如此关键字必须用作变量初始值设定项?例如这将产生语法错误:
public unsafe class UnsafeStream
{
byte* buffer;
public UnsafeStream(int capacity)
{
this.buffer = stackalloc byte[capacity]; // "Invalid expression term 'stackalloc' / ; expected / } expected"
}
}
但是重新分配本地临时的结果不会:
public UnsafeStream(int capacity)
{
byte* buffer = stackalloc byte[capacity];
this.buffer = buffer;
}
为什么第一个版本不被允许,如果我尝试第二个版本会发生什么邪恶的事情?
最佳答案
您的堆栈大致如下所示:
[stuff from earlier calls][stuff about where this came from][this][capacity]
^You are here
然后你执行stackalloc
,这会向堆栈添加两个东西,指针和指向的数组:
[stuff from earlier calls][stuff about where this came from][this][capacity][buffer][array pointed to by buffer]
^You are here
然后当您返回最近放入堆栈的东西时,当前函数的局部变量、它的返回地址和 stackalloc
ed 缓冲区都被简单地忽略(这是stackalloc
的优点,忽略内容既快速又容易):
[stuff from earlier calls][stuff about where this came from][this][capacity][buffer][array pointed to by buffer]
^You are here
它可以被下一个方法调用覆盖:
[stuff from earlier calls][stuff about where this came from][this][new local1][new local2]o by buffer]
^You are here
你所提议的是一个私有(private)字段,也就是说堆上对象的一部分(不同的内存,管理方式不同)持有一个指向缓冲区的指针,该缓冲区已被完全覆盖不同的数据,不同的类型。
立即的后果是:
- 尝试使用
buffer
现在很麻烦,因为其中一半被项目覆盖,其中大部分甚至不是字节。 - 现在尝试使用任何本地都充满了麻烦,因为将来对
buffer
的更改可能会在随机位置用随机字节覆盖它们。
这只是考虑这里涉及的单个线程,不要介意具有单独堆栈的其他线程可能能够访问该字段。
它也不是很有用。您可以通过足够的努力强制一个字段将地址保存到堆栈中的某个位置,但是用它做的事情并不多。
关于c# - 为什么必须将 stackalloc 用作变量初始值设定项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32343220/