我有一个包含字段的有序结构..
[StructLayout(LayoutKind.Explicit)]
public unsafe struct RunBlock_t {
[System.Runtime.InteropServices.FieldOffset(0)] public fixed byte raw[512];
}
Run Code Online (Sandbox Code Playgroud)
如果我在一个函数内声明这个并想要使用指针,它工作正常..
{
RunBlock_t r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
Run Code Online (Sandbox Code Playgroud)
但是如果我在范围之外声明变量,则需要一个固定的实现
RunBlock_t r;
{
r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i=0; i<510; i++) ptr[i]=0;
}
Run Code Online (Sandbox Code Playgroud)
为什么这种行为上的差异?
---编辑-----
只想再次说明任何其他排列都不起作用.
unsafe void foo() {
RunBlock_t r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i = 0; i < 512; i++) ptr[i] = 0;
}
Run Code Online (Sandbox Code Playgroud)
生成您不能使用fixed语句获取已修复表达式的地址,也不能编译.
RunBlock_t r;
unsafe void foo() {
r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
Run Code Online (Sandbox Code Playgroud)
生成您不能使用未固定表达式中包含的固定大小缓冲区.尝试使用fixed语句.并且不编译.
你的问题没有任何意义.您可能会将数组与指针混淆,可能是因为在C和C++中,数组在大多数上下文中都会快速降级为指针,包括[]下标运算符.
但这是C#.数组和指针是完全独立的动物(尽管你可以将数组强制转换为指针,但你必须在fixed语句中这样做,以确保指针保持有效).你应该比较
{
RunBlock_t r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
Run Code Online (Sandbox Code Playgroud)
至
RunBlock_t r;
{
r = new RunBlock_t();
for (int i=0; i<512; i++) r.raw[i]=0;
}
Run Code Online (Sandbox Code Playgroud)
两者都使用数组.要不然
{
RunBlock r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i=0; i<512; i++) ptr[i]=0;
}
Run Code Online (Sandbox Code Playgroud)
至
RunBlock_t r;
{
r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i=0; i<512; i++) ptr[i]=0;
}
Run Code Online (Sandbox Code Playgroud)
两者都使用指针.
然后你会看到变量声明的范围与需要完全没有关系fixed.
不幸的是,你稍微混淆了这个问题。如果我准确地复制问题,那么效果很好:
{
RunBlock_t r = new RunBlock_t();
for (int i = 0; i < 512; i++) r.raw[i] = 0;
}
Run Code Online (Sandbox Code Playgroud)
和这个:
RunBlock_t r;
{
r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i = 0; i < 510; i++) ptr[i] = 0;
}
Run Code Online (Sandbox Code Playgroud)
提高:
不能使用固定语句来获取已经固定的表达式的地址
如果我们删除fixed,它就会起作用。
你应该显示的是函数签名,即
RunBlock_t r;
unsafe void Bar()
{
{
r = new RunBlock_t();
fixed (byte* ptr = r.raw) for (int i = 0; i < 510; i++) ptr[i] = 0;
}
}
Run Code Online (Sandbox Code Playgroud)
现在意思变得更清楚了。您会看到,当您用于fixed访问值中的固定缓冲区时,您实际上并没有修复缓冲区,也没有修复该值;您实际上要修复的是包含对象,即具有该字段的对象r。这是为了防止 GC 在堆栈上移动它,如果我们当时将它作为指针访问,这会很糟糕。在上面的示例中,我们的表达式是 real fixed (byte* ptr = this.r.raw),固定的内容是:this。
如果我们只有一个结构作为本地结构,情况会有所不同。本地人在堆栈上;它们(正如之前的消息所暗示的)已经修复了;GC 永远不会重新定位堆栈。
所以:
fixed- 您只需直接将其作为指针访问(通过ldloca)fixed, 在操作期间将对象固定到位ref RunBlock_t(即参数),则必须使用它fixed 以防万一它是对象上的字段;如果引用最终解析为堆栈,则不需要执行任何操作someArray[8](因为您可以就地操作数组的内容)| 归档时间: |
|
| 查看次数: |
1844 次 |
| 最近记录: |