C#中的void*是什么?

13

我正在查看一个VC++6.00程序的源代码。我需要将这个源代码转换为C#,但是我不理解在这个示例中(void*)是什么意思?

glTexImage2D(
     GL_TEXTURE_2D,
     0,
     GL_RGBA8,
     IMAGE_WIDTH,
     IMAGE_HEIGHT,
     0,
     PIXEL_FORMAT,
     GL_UNSIGNED_BYTE,
     (void*)imageData
 );

在这段代码中,imagedata是一个指针 byte* imageData


1
void* 可以是任何东西。它应该根据上下文进行翻译 - 在您的情况下可能是 byte[] - Konrad Rudolph
7个回答

24

一般而言,void* 在 C# 代码中会被转换为 IntPtr

补充更多信息:在 .NET/C# 中,IntPtr 常常表现得像一个不透明的句柄。你不能直接取消引用它,也无法从它那里获取“大小”信息(例如指向哪个数组的大小),它也不会告诉你它指向的数据类型——甚至不知道它是否是指针。当你将 C/C++ 代码翻译成 C# 代码时,如果遇到了 void*,应该使用 IntPtr 直到你更清楚地了解正在处理的内容。

pinvoke.net 网站为 glTexImage2D 提供了两个条目,具体取决于图像数据存储的位置。如果图像数据存储在 .NET/C# 中的托管 byte[] 中,则调用传递 byte[] 的版本。如果图像数据存储在非托管内存中,并且在 C# 代码中只有 IntPtr 对其数据进行操作,则调用传递 IntPtr 的版本。

来自于 pinvoke.net opengl32 的例子:

[DllImport(LIBRARY_OPENGL)] protected static extern void glTexImage2D (
    uint target,
    int level, 
    int internalformat, 
    int width, 
    int height, 
    int border, 
    uint format, 
    uint type, 
    byte[] pixels);
[DllImport(LIBRARY_OPENGL)] protected static extern void glTexImage2D (
    uint target, 
    int level, 
    int internalformat, 
    int width, 
    int height, 
    int border, 
    uint format, 
    uint type, 
    IntPtr pixels);

1
这种情况下会起作用吗?我怀疑传递的是一个字节数组。 - Robert Harvey
因为您是第一个给出真正答案的人,反映了他想知道C#等效性的事实。 - Beachwalker
1
@Beachwalker 或许有点过早了。IntPtr 并不能完成很多任务,根据使用情况,另一种类型可能更加适合。 - Konrad Rudolph
1
@RobertHarvey 这就是我说“一般情况”的原因。有大量具体情况,每种情况都应该以适当的方式处理。Interop 代码不是您想要从“我猜测…”做出决策的领域。 - Sam Harwell
@KonradRudolph 有示例吗?在不使用unsafe关键字进行交互操作时,IntPtr是我认为最常见的等效方式。为什么要过早下结论呢?还有其他人没有回答关于C#中等效方式的问题,只是写了一个(void)指针是什么。 - Beachwalker
@Beachwalker 为什么过早:因为细节简单地缺失了,OP 应该提供它们(请参见我对Jonathan好答案的评论)。至于 IntPtr 是互操作的最常见等效物 - 我不认为这是情况(您通常不需要泛型性,您可以直接使用对象并使用适当的类型),但即使假设它是,我们也不知道 OP 是否正在处理互操作或者他们是否想要将整个代码放在 C# 中。 - Konrad Rudolph

8

在C#中,它通常是一个IntPtr

以下是如何从C#调用此函数的示例:

Bitmap bitmap = new Bitmap("blah");
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, 4, bitmap.Width, bitmap.Height, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_BYTE, bitmap.Scan0);

if(bitmap != null) {
    bitmap.Dispose();
}

来源:http://www.gamedev.net/topic/193827-how-to-use-glglteximage2d--using-csgl-library-in-c/

如果你有一个包含有效图像的byte[],你可以像这样将其加载到位图中:

public static Bitmap BytesToBitmap(byte[] byteArray)
{
    using (MemoryStream ms = new MemoryStream(byteArray))
    {
        Bitmap img = (Bitmap)Image.FromStream(ms);
        return img;
    }
}

如果这给你带来了麻烦,或者你的数据不是Win32库可以处理的类型,你可以使用Marshal从byte[]直接获取IntPtr。
IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);

// Call your function here, passing unmanagedPointer to it

Marshal.FreeHGlobal(unmanagedPointer);

来源: 如何在C#中从byte[]获取IntPtr


好的示例作为答案很好,因为它与问题示例(都是OpenGL)处于相同的上下文中。 - Beachwalker

3
正如Jonathan D在他的数据中解释的那样,void*是C语言表示一种通用类型但不能直接使用的方法。它是C语言实现通用接口的方式,尽管在C#中有一个直接等价的方法(System.IntPtr),但你可能想使用其他方法,因为C#有更好的处理通用数据的方式,并且你不确定你需要传递通用数据。
由于你将图像数据传递给函数,因此在C#中有几种可能表示void*
  • byte[] 传递原始图像数据到函数
  • System.Drawing.Color[,]如果你正在处理更高级的点数据(不太可能)
  • System.Drawing.Image如果你想在更高层次上处理图像数据,则这可能是一个好主意;如果可以的话,这是一个好的选择
  • IntPtr如果你有一个低级缓冲区,并且该函数在内部将数据传递给一个C API而不是自行处理它。
没有更多关于你将如何使用代码和翻译哪些部分的信息,就无法确定你在这里需要哪些类型。

2

正如已经提到的,IntPtr是等效的。

在C#中,你只能在unsafe上下文中使用指针,例如:

void MyMethod(IntPtr ptr)
{
  unsafe
  {
      var vptr = (void*) ptr;
      // do something with the void pointer
  }
}

2

这段文字中提到了将imageData转换为(void*)类型,实际上是告诉编译器将该值视为(void*)类型。

根据我的经验,void*是指向非特定类型的指针。


如果要将示例转换为C#,则不必过于担心C++中的转换方式。只需确保将正确的类型传递给相应的C#函数即可。


1

Void实际上是没有任何内容的,

使用void有三种方式:

  • 参数: int myFunc(void) -- 函数不接收任何参数。

  • 返回值: void myFunc(int) -- 函数不返回任何值。

  • 通用数据指针: void* data -- 'data' 是指向未知类型数据的指针,不能被引用。

在这种情况下,它是一个通用数据指针。


10
这完全没有回答他的问题,我对点赞感到困惑。他想知道在C#中等价于void*的是什么,而不是void是什么的解释。 - Adam Sills
@Adam 作为点赞者之一,我来解释一下:虽然我对这个答案并不完全满意(就像你提到的那样),但这是第一个以简明扼要的方式解释 void* 是什么的答案。如何将其翻译成 C# 取决于它的用途,而 OP 还没有透露过太多信息。 - Konrad Rudolph

1

void*是指向未定义类型对象的指针,在C#中有不同的表示方法:

  1. 在不安全代码中,它可以表示为未格式化的pointer
  2. 作为IntPtr,通常用于管理托管对象和非托管对象之间的指针传递。
  3. object用于未指定的但是受管理的对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接