2009-10-30 104 views
1

我发现从网上的代码中,我无法理解这行: -说明这个C#代码:byte * p =(byte *)(void *)Scan0;

byte* p = (byte*)(void*)Scan0; 

有SCAN0是System.IntPtr。 它是C#.Net的代码。 Plz解释上述行。

完整的代码如下。这是用灰度转换图像的代码。

public static Image GrayScale(Bitmap b) 
    { 

     BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 

     int stride = bmData.Stride; 
     System.IntPtr Scan0 = bmData.Scan0; 

     unsafe 
     { 
      byte* p = (byte*)(void*)Scan0; 

      int nOffset = stride - b.Width * 3; 

      byte red, green, blue; 

      for (int y = 0; y < b.Height; ++y) 
      { 
       for (int x = 0; x < b.Width; ++x) 
       { 
        blue = p[0]; 
        green = p[1]; 
        red = p[2]; 

        p[0] = p[1] = p[2] = (byte)(.299 * red + .587 * green + .114 * blue); 

        p += 3; 
       } 
       p += nOffset; 
      } 
     } 

     b.UnlockBits(bmData); 

     return (Image)b; 
    } 

我了解所有的代码,但只有这一行的问题。

byte* p = (byte*)(void*)Scan0; 
+10

它恰好拼写为“please”。 – 2009-10-30 03:10:00

回答

5

首先IntPtr转换为void指针。然后到一个byte指针。这是unsafe的代码。

更多不安全的代码: http://msdn.microsoft.com/en-us/library/aa288474%28VS.71%29.aspx

正如罗伯特·哈维指出,一个指针是一个内存位置。在C/C++中,数组与这个概念密切相关。当它做方括号时,它基本上是调整地址。

+0

谢谢先生,我理解指针和不安全代码的概念。你能否给出一些关于void指针的更多解释。 – qulzam 2009-10-30 02:57:43

+3

无效指针以非常基本的方式是指向无特定类型的指针。所以,你得到一个指向不引用任何类型的地址的指针,简单地说就是该地址的数据。然后,你可以自由地将它投射到任何你喜欢的地方。在这个例子中,他们把一个Int赋给一个void(没有)。 void指针(原始内存地址)然后被转换为一个字节的地址。 (好主人,这是我从事此工作以来一直存在的,有人请纠正我,如果我错了)。 – 2009-10-30 03:05:57

1

它看起来奇怪,但我不知道C#那么好。它可能是有一些问题,直接铸造System.IntPtrbyte*,但不能与System.IntPtrvoid*void*byte*

最终的结果可能是一样的,如果你用C投int*char*:能够反引用p得到整数的单字节(假设CHAR_BIT是8 C实现)。

1

查看关于不安全代码的教程。这将解释什么的代码行手段,以及如何将它用于其他类型的除了字节:

http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

从本质上讲,不安全的代码,允许你使用C风格的指针。

+0

我明白不安全的代码,但是有一些混淆(byte *)(void *)的含义是什么, – qulzam 2009-10-30 03:03:07

4

你的问题听起来就好像你问什么代码是干什么的,但基于一些您的意见,我认为你是它的第一投射到一个空指针为什么后。

您可能会对此感到困惑,因为没有理由先将Scan0投射到void *。转换为字节*也可以。

0

有没有可能,你需要转换为void,以避免它执行一些自投代码的对象?

2

IntPtr有一个显式操作符(void *),它允许强制转换为void *。如果你试图直接从IntPtr转换到别的东西,那么编译器会禁用,因为只有void * cast被定义为IntPtr类。另请参阅IntPtr :: ToPointer()。

从void *的为字节*铸造是由编译器,因为此时允许,如果你不知道你在做什么,你就麻烦了。