如何使用 swig 从 `unsigned int *` return `uint []`

How to return `uint []` from `unsigned int *` using swig

我必须包装以下 c++ 函数:

class Foo {
  unsigned int *getVector3();
};

成员函数getVector3,return是一个(固定的)3D数组,例如[1,2,3]。我应该如何使用 arrays_csharp.i 作为 return 类型?文档仅针对输入参数进行描述:

在我的例子中,return 类型始终是一个固定大小的数组(包含 3 个元素)。

我有一个答案,尽管在我看来它并不完全令人满意。不过,这主要受限于我对 C# 的了解,所以你可以让它比我做得更好。

我认为 arrays_csharp 不是您要查找的内容。它似乎与固定内存有关,因此它可以用作函数的输入,但在您的场景中,您已经分配了想要使用的内存。

这很容易(而且对于 3D 矢量来说相当便宜),通常使用 System.InteropServices.Marshal。所以我用你想要的东西组合了一些类型图:

%module test
%typemap(csout,excode=SWIGEXCODE) unsigned *getVector {
    global::System.IntPtr cPtr = $imcall;$excode
    int[] tmp = new int[3];
    // I have no idea why Marshal.Copy does not seem to have any support for unsigned types...
    global::System.Runtime.InteropServices.Marshal.Copy(cPtr, tmp, 0, 3);
    // There is probably a better way to go from int[3] -> uint[3], but it is not obvious to me
    return new $typemap(cstype, $*1_type)[3]{($typemap(cstype, $*1_type))tmp[0],($typemap(cstype, $*1_type))tmp[1],($typemap(cstype, $*1_type))tmp[2]};
}

%typemap(cstype) unsigned *getVector "$typemap(cstype, $*1_type)[]"

%inline %{
unsigned *getVector() {
  static unsigned arr[3] = {1,2,3};
  return arr;
}
%}

注意事项:

  • $typemap(cstype, $*1_type) 是找到与我的 C 元素类型对应的 C# 类型的奇特方式。我倾向于尝试避免在类型映射中显式编写类型,因为它使事情更通用。
  • 话虽如此,Marshal.Copy 似乎只适用于有符号数组类型,而不适用于无符号数组类型,原因我不太明白。而且我看不到为无符号类型找到相应有符号类型的自动方法,所以我不得不明确地写 int[]
  • 我不确定 signed -> unsigned 转换实际上是 C# 中明确定义的行为。对于设置了最后一位的值,这可能无法正常工作。您可以通过为 tmp 增加 int 类型的大小来解决这个问题。 (例如,使用 int64 而不是 int32,但这并不漂亮)
  • 应该有比我所做的更好的方法来转换整个数组,但我不太了解 C# 语言。

这就足够了,我可以 运行 以下程序(使用 Mono)并获得预期的输出

public class runme {
  static void Main(string[] args) {
    uint[] arr = test.getVector();
    System.Console.WriteLine(arr[0]);
    System.Console.WriteLine(arr[1]);
    System.Console.WriteLine(arr[2]);
  }
}

如果有用的话,我们可以做更多的工作来使这个通用(即其他大小的向量、其他数据类型 int16[4] 等)。