如何从 Swift 中的 C 函数获取数组?

How to get an array from a C function in Swift?

我在 Swift 代码中使用 C 函数输出一个数组。该函数不是 return 数组,因为显然在 C 中,不鼓励函数 returning 数组。因此,该函数采用 in-out 参数(作为指针)并将数组放在那里。

C函数:

void kRing(H3Index origin, int k, H3Index* out);

H3Index*是取数组的out参数。但是,如何从 Swift 中的此函数获取数组? H3Index*out参数,指向一个整数。而且,显然在 C 中,您可以指向一个整数,将该指针传递给一个函数,并且该函数可以在该指针的位置放置一个数组(即使它指向一个整数)。

但是由于Swift的类型安全,这使得从函数中获取数组变得困难。 Swift版本:

kRing(origin: H3Index, k: Int32, out: UnsafeMutablePointer<H3Index>!)

我的 Swift 实现:

let h3Index: H3Index = 600022775385554943 // integer
let k: Int32 = 2 // integer
var result = H3Index() // the in-out parameter (must be integer to satisfy Swift's type safety)
_ = withUnsafeMutablePointer(to: &result) { kRing(h3Index, k, [=13=]) }
print(result)

并打印结果(带有错误的访问错误,我现在不关心)。但是当它应该是一个数组时,结果却是一个整数。这是怎么做到的?

C实现,供参考:

H3Index indexed = 0x8a2a1072b59ffffL; // 64-integer (hex)
int k = 2; // integer
int maxNeighboring = maxKringSize(k); // integer

H3Index* neighboring = calloc(maxNeighboring, sizeof(H3Index)); // the out parameter (a pointer to an integer and/or array)

kRing(indexed, k, neighboring); // the function

for (int i = 0; i < maxNeighboring; i++) {
    if (neighboring[i] != 0) {
        // iterate through array
    }
}

在 C 中,

H3Index* neighboring = calloc(maxNeighboring, sizeof(H3Index));
kRing(indexed, k, neighboring);

为类型 H3IndexmaxNeighboring 个元素分配内存并将内存初始化为零。然后将该内存块的地址(即第一个元素的地址)传递给 kRing 函数。

可以从 Swift 调用 callocfree,但更容易使用的 API 是 Unsafe(Mutable)(Buffer)Pointer 及其 allocate()deallocate() 方法:

let neighboring = UnsafeMutableBufferPointer<H3Index>.allocate(capacity: maxNeighboring)
neighboring.initialize(repeating: 0)
kRing(indexed, k, neighboring.baseAddress)

现在您可以使用

打印值
for i in 0..<maxNeighboring { print(neighboring[i]) }

或者只是(因为 Unsafe(Mutable)BufferPointer 是一个 集合 可以迭代:

for neighbor in neighboring { print(neighbor) }

最终你必须释放内存以避免内存泄漏:

neighboring.deallocate()

更简单的方案是定义一个Swift数组,将元素存放的地址传给C函数:

var neighboring = Array<H3Index>(repeating: 0, count: maxNeighboring)
kRing(indexed, k, &neighboring)

for neighbor in neighboring { print(neighbor) }

neighboring现在是一个局部变量,所以当变量超出范围时,内存会自动释放。