我在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;
}
为什么不允许第一个版本,如果我尝试第二个版本会发生什么邪恶的事情?
答案 0 :(得分:3)
你的筹码看起来非常像这样:
[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缓冲区都被忽略了(这是{的优点之一) {1}},忽略东西快速而简单):
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
现在充满了因为其中一半被项目覆盖,其中大多数都不是偶数字节。buffer
的未来更改可能会在随机位置随机字节覆盖它们。而且这只是在考虑这里涉及的单个线程,不要介意具有单独堆栈的其他线程也许能够访问该字段。
它也不是很有用。你可以强迫一个字段在一个堆栈的某个地方用足够的努力保存一个地址,但是没有那么好的人可以用它做。