【问题标题】:How to typecast data pointed by void pointer to a fixed size int array in C#?如何将 void 指针指向的数据类型转换为 C# 中固定大小的 int 数组?
【发布时间】:2014-11-06 02:30:52
【问题描述】:

这类似于以下 SO 问题:

cast-void-pointer-to-integer-array

c-pointers-pointing-to-an-array-of-fixed-size

但是,不同之处在于我想在 C# 中使用“不安全”功能来实现这一点,通过它我们可以使用指针。

例如

以下代码在 C 中工作:

int (*arr)[10] = (int (*)[10]) ptr;

其中'ptr'是空指针。这在 C# 中如何实现?

【问题讨论】:

  • 如何在 C# 中获取指针?您可以以int* 开头,也可以这样接收。如果您收到void*,则必须对其进行强制转换才能使用它。
  • 你能解释一下你为什么要这样做吗?另外,我相信 C# 类型系统没有固定大小的数组。
  • @xxbbcc 和:我知道我可以将 void 指针转换为 int 指针,但是,我希望将其转换为固定长度的数组。当有一些标准的第三方库函数将固定长度的数组作为输入时,这有时是必要的。例如无效标准函数(int [])。我不能只传递一个整数指针给这个函数。

标签: c# pointers casting unsafe


【解决方案1】:

我不完全确定这就是你要找的东西,但一个例子是这样的:

int[] items = new int[10];

unsafe
{
    fixed ( int* pInt = &items[0] )
    {
        // At this point you can pass the pointer to other functions
        // or read/write memory using it.
        *pInt = 5;
    }
}

在获取数组的地址时,您必须获取数组中第一项的地址 - 因此在上面的示例中为 &items[0]

如果您将指针作为void* 函数参数接收,则必须将其强制转换为函数内部:

public static unsafe void F ( void* pMem )
{
    int* pInt = (int*) pMem;

    // Omitted checking the pointer here, etc. This is something
    // you'd have to do in a real program.
    *pInt = 1;
}

如果您从外部来源收到void*,您必须以某种方式知道有多少字节(或整数等)可以通过指针安全访问。数据可能由特殊值分隔(如终止 0 或其他内容),或者您需要计数或字节/元素才能通过指针安全地访问内存。

更新

下面是调用 C 实现的非托管函数的示例:

// Function declaration in C
#define EXPORTFUNC __declspec(dllexport)
#define MYDLLAPI __declspec(nothrow) WINAPI

EXPORTFUNC int MYDLLAPI MyFunc1 ( byte* pData, int nDataByteCount );

// Import function in C#
[DllImport ( "My.dll" )]
private static extern int MyFunc1 ( byte* pData, int nDataByteCount );

// Call function with data (in unsafe class / method)
byte[] byData = GetData ( ... ); // returns byte array with data

fixed ( byte* pData = byData )
{
    int nResult = MyFunc1 ( pData, byData.Length );

    ...
}

MSDN 有更多关于各种指针操作的示例。另外,这里还有一个 article 关于编组数组。

【讨论】:

  • 感谢您的回答。我知道我可以访问 void 指针指向的内存,方法是将其转换为 int 指针,然后递增指针,然后再次访问下一个位置,依此类推。但是,如果我必须将此数据传递给其他接受固定大小数组的标准第三方函数,我无法控制该第三方标准函数中的上述逻辑,因为我无法编辑它,也不应该编辑它。
  • @genonymous 这取决于 3rd 方函数的确切期望。如果它期望 int* 包含 5 个项目的数组,那么在 C# 中,您可以创建一个包含 5 个 int-s 的数组,获取第一个元素的地址,然后将该指针传递给第 3 方调用。数组是连续的,因此知道第一个元素的地址、元素的大小和数组中的项目数可以告诉您有关数组的所有信息。
  • @genonymous 我为你添加了一个调用外部函数的小例子。
  • @genonymous 我现在才看到您的其他评论并意识到我可能误解了您的要求。我在关于声明签名以将固定大小的数组传递给非托管函数的答案中添加了另一篇文章。
【解决方案2】:

您可以简单地将其转换为 int* 指针.. 希望最好.. 显然:

// unsafe {}

var a = stackalloc int[5];
a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;

var v = (void*) a; // cast to void as example

for (var i = 0; i < 5; i++)
    Console.WriteLine((*(int*)v)++); // back to int - 1, 2, 3, 4, 5

这就是说.. 你必须小心边界检查。 AFAIK 没有允许边界的直接翻译。

【讨论】:

  • 感谢您的回答。但我知道上面的逻辑,我想要的是允许界限的直接翻译。我知道如何在 C 中做到这一点,并且在我嵌入问题的两个 SO 问题中也提到了这一点。我正在寻找一种 C# 方式来做到这一点。
猜你喜欢
  • 2019-05-14
  • 2021-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 2014-07-22
相关资源
最近更新 更多