Как получить массив из функции C в Swift? - PullRequest
1 голос
/ 28 февраля 2020

Я работаю с функцией C в моем коде Swift, который выводит массив. Функция не возвращает массив, потому что, по-видимому, в C функциям не рекомендуется возвращать массивы. Поэтому функция принимает параметр 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>!)

Реализация My 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, $0) }
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
    }
}

1 Ответ

1 голос
/ 28 февраля 2020

In C,

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

выделяет память для maxNeighboring элементов типа H3Index и инициализирует память на ноль. Адрес этого блока памяти (который является адресом первого элемента) затем передается в функцию kRing.

Это можно вызывать calloc и free из Swift, но более простой в использовании 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]) }

или justs (поскольку 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 теперь является локальной переменной, поэтому память автоматически освобождается, когда переменная выходит из области видимости.

...