Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对'的要求;固定的';在C中似乎不一致#_C#_Pointers_Fixed - Fatal编程技术网

C# 对'的要求;固定的';在C中似乎不一致#

C# 对'的要求;固定的';在C中似乎不一致#,c#,pointers,fixed,C#,Pointers,Fixed,我有一个包含字段的有序结构 [StructLayout(LayoutKind.Explicit)] public unsafe struct RunBlock_t { [System.Runtime.InteropServices.FieldOffset(0)] public fixed byte raw[512]; } 如果我在一个函数中声明了这一点,并希望使用指针,那么它可以正常工作 { RunBlock_t r = new RunBlock_t(); for (int

我有一个包含字段的有序结构

[StructLayout(LayoutKind.Explicit)]
public unsafe struct RunBlock_t {
    [System.Runtime.InteropServices.FieldOffset(0)]  public fixed byte raw[512];
}
如果我在一个函数中声明了这一点,并希望使用指针,那么它可以正常工作

{
  RunBlock_t r = new RunBlock_t();
  for (int i=0; i<512; i++) r.raw[i]=0;
}
{
RunBlock_t r=新的RunBlock_t();

对于(int i=0;i),你的问题没有任何意义。你把数组和指针混淆了,可能是因为C和C++中的数组和数组在大多数上下文中都会迅速退化为指针,包括<代码> [C]>下标操作符。 但这是C#。数组和指针是完全独立的(虽然可以将数组强制为指针,但必须在
fixed
语句中执行,以确保指针保持有效)。您应该进行比较

{
  RunBlock_t r = new RunBlock_t();
  for (int i=0; i<512; i++) r.raw[i]=0;
}
{
RunBlock_t r=新的RunBlock_t();

对于(int i=0;i很遗憾,您对问题有点混淆。如果我完全从问题复制,则此操作很好:

    {
        RunBlock_t r = new RunBlock_t();
        for (int i = 0; i < 512; i++) r.raw[i] = 0;
    }
现在,含义变得更清楚了。您可以看到,当您使用
fixed
访问值中的固定缓冲区时,您实际上并没有固定缓冲区,也没有固定值;您实际固定的是包含对象,即具有
r
字段的对象。这是为了防止GC在堆栈上移动它,w如果我们当时将其作为指针访问,这将是不好的。在上面的示例中,我们的表达式实际上是固定的(byte*ptr=this.r.raw)
,而被固定的东西是:
this

如果我们只有有一个结构作为局部结构,这是不同的。局部结构在堆栈上;它们(如前面的消息所暗示的)已经被修复;GC永远不会重新定位堆栈

因此:

  • 如果将结构作为局部变量,则无需使用
    fixed
    -您只需将其作为指针直接访问(通过
    ldloca
  • 如果有一个结构是对象中的字段,则需要使用
    fixed
    ,在操作期间将对象固定到位
  • 在向结构传递引用(即
    ref RunBlock\t
    参数)的情况下,必须使用
    fixed
    ,以防万一它是对象上的一个字段;如果该引用最终解析为堆栈,则无需执行任何操作
  • 请注意,这里关于“对象上的字段”的所有内容也同样适用于“数组中的值”,即如果我们谈论的是
    someArray[8]
    (因为您可以在原位操作数组的内容)

这…实际上是非常不一致的。很有趣。我希望两者都需要
fixed
@marcgravel你似乎在回答我所有的问题:)--是的,如果我在第一种情况下尝试使用fixed,它会给我一个错误,说我不能在固定指针上使用fixed…(考虑到raw已经在结构中声明为fixed)@MarcGravell:第一种情况(它是数组的下标,没有任何指针)是什么情况您希望需要
fixed
?@Ben,因为这就是您使用它们的方式-请参阅MSDN:@Marc:这是一个非常无用的链接。第二个案例编译时不会出现警告,说我需要在其中添加一个fixed。第三个案例也会失败,说我无法将fixes语句应用于固定指针(请注意,raw在结构中是固定的)。这里有确切的错误。案例2:无法使用未固定表达式中包含的固定大小缓冲区。请尝试使用fixed语句。案例3:无法使用fixed语句获取已固定表达式的地址expressio@reza:我的答案中的任何代码出现故障都可能是编译器错误。我将看看是否可以获得一些Microsoft team个成员(例如Eric Lippert)注意。固定缓冲区不是数组。在这个问题中根本没有显示数组。@Ben该成员是与实例的相对偏移量。在本例中,偏移量为零。在所有有意义的方面,它都是作为指针访问的:我怀疑(我没有检查)如果我们看一下IL,那里有一个ldloca…ldloca的结果是(引用MSDN)“结果是一个瞬态指针(类型*)。”很好地解释了第一次显示的代码(局部变量在两个作用域中)与后来发布的实际代码(类成员)之间的差异。仍然不确定为什么C#编译器会使用原始指针来访问固定缓冲区,而不是跟踪指针(aka
interior\u ptr
)。感谢您的解释!因此,根据结构内部的结构定义,该字段是固定的,而不是实际的结构。因此,尽管r.raw定义为固定的,但由于GC,它仍然可以四处移动。默认情况下,堆栈是固定的,堆不是。您需要执行堆alloc以使堆中的某些内容固定。如果这样做,你能将分配内存强制转换为结构并以这种方式访问它吗?或者这对c#?Thnx来说太难看了。@reza是的,如果你有一个指针(来自外部分配,或stackalloc,等等),您可以将其强制为结构,而不必将整个内容视为bytes@Ben可能是因为c#只声明了一种类型的指针,而且它需要对所有类型的指针都起作用?但听起来更像是一个pin#street…?(不完全是我的领域;pin也可能明确发生)@马克:但我们并不局限于C向用户代码公开的指针类型,C编译器生成的MSIL可以使用CLR公开的任何语义,其中包括
interior\u ptr
行为(显然在MSIL中不是这样称呼的)
    RunBlock_t r;
    unsafe void foo() {
      r = new RunBlock_t();
      for (int i=0; i<512; i++) r.raw[i]=0;
    }
{
  RunBlock_t r = new RunBlock_t();
  for (int i=0; i<512; i++) r.raw[i]=0;
}
RunBlock_t r;
{
  r = new RunBlock_t();
  for (int i=0; i<512; i++) r.raw[i]=0;
}
{
  RunBlock r = new RunBlock_t();
  fixed (byte* ptr = r.raw) for (int i=0; i<512; i++) ptr[i]=0;
}
RunBlock_t r;
{
  r = new RunBlock_t();
  fixed (byte* ptr = r.raw) for (int i=0; i<512; i++) ptr[i]=0;
}
    {
        RunBlock_t r = new RunBlock_t();
        for (int i = 0; i < 512; i++) r.raw[i] = 0;
    }
    RunBlock_t r;
    {
        r = new RunBlock_t();
        fixed (byte* ptr = r.raw) for (int i = 0; i < 510; i++) ptr[i] = 0;
    }
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;
    }
}