指针运算和C#编译器

时间:2009-11-02 18:11:17

标签: c# compiler-construction pointers void-pointers

为了学习目的,我最近查看了一个使用Win32 WriteFile的现有程序集(使用Reflector)。实施是:

Write(IntPtr handleFile, void* bufferData, uint length){
void* buffer = bufferData
while (length > 0)
{
  uint wrtn;
  if (!WriteFile(handle, buffer, len, out wrtn, IntPtr.Zero))
  {
     // Do some error handling
  }
  // This does not compile, because of the cast but also simply because void* does not have += operators (it is unknown size).
  buffer += (void*)wrtn;
  len -= wrtn;
}

}

实际上最后两行是有问题的...例如,编译器抱怨你不能将uint转换为void *。另外,在void *上使用+ =或偶数+是不可能的,因为它不是已知的大小。

Write(IntPtr handleFile, void* bufferData, uint length){
    byte* buffer = (byte*)bufferData
    while (length > 0)
    {
      uint wrtn;
      if (!WriteFile(handle, (void*)buffer, len, out wrtn, IntPtr.Zero))
      {
         // Do some error handling
      }
      // This works! I can add to a byte*
      buffer = buffer + wrtn; // I could also have used buffer += wrtn
      len -= wrtn;
    }
}

上面的代码确实有效,但最后几行仍然会编译为:

buffer += (byte*)wrtn;

我不明白为什么并且非常想知道编译器为什么会以这种方式运行:

  1. 为什么它会像这样生成强制转换(为什么在用户编写的代码中不接受这样做?)
  2. 第一个例子中,void *上的+ =运算符是什么?什么原始代码生成缓冲区+ =(void *)wrtn其中buffer也是void * ????

2 个答案:

答案 0 :(得分:1)

对于你的第二点,void *没有大小信息,所以编译器不知道增加指针的数量。它应该增加sizeof(double)吗?只有类型信息才知道会发生什么。

编辑:实际上这也适用于你的第一点。编译器需要知道其递增的数据类型的大小。 Void *没有大小信息,所以通过转换为字节*,让编译器知道它需要通过sizeof(byte)* wrtn递增指针。

Edit2:有了你的澄清,你似乎在问为什么Reflector将代码作为void *而不是正确的类型(byte *)发出。很可能这是由于从参数类型中提取的类型信息,并且在该方法中有点天真地使用。这可能是Reflector比编译器更多的问题。

这个指针代码也可能在IL中丢失了它的类型信息,我还没有测试过它,但是它可能不会将输入信息(除了数据的大小)带入IL,以便Reflector正确发出(正常'安全'IL应始终具有此类型信息)。如果是这种情况,Reflector可能默认为void *或最近的推断类型。

答案 1 :(得分:0)

  

为了学习目的,我最近查看了一个现有的程序集(使用Reflector)

这里唯一的问题是使用Reflector - 显然,从IL推断出原始的C#代码并不是那么好。 IL本身是正确的,并且没有强制转换(不需要强制转换 - 在IL中,您在堆栈上按下指针和整数参数,然后执行加/减)。反射器是错误的。