Как передать сложные быстрые типы данных в C типы данных при вызове собственных функций в iOS / MacOS? - PullRequest
0 голосов
/ 13 апреля 2020

Мне удалось получить базовый c dylib, который я включил в каркас, который позволяет мне передавать Int и возвращает и Int работает, но как мне передать и вернуть более сложные типы данных, такие как указатель, байтовые массивы или фактические структуры данных от swift до C dylib?

Существуют ли учебники или ресурсы для сопоставления / передачи / преобразования из типа данных swift в тип данных C и наоборот, как в JNI для java?

1 Ответ

1 голос
/ 13 апреля 2020

Пример интерпретации структуры C и динамического извлечения функций из c -дилиба на стороне Swift может выглядеть следующим образом:

. c Файл

Person *get_person() {
    Person *p = malloc(sizeof(Person));
    p->first_name = strdup("Branford");
    p->last_name = strdup("Marsalis");
    p->age = 60;
    return p;
}

void free_person(Person *person) {
    free(person->first_name);
    free(person->last_name);
    free(person);
}

.h Файл

typedef struct {
    char *first_name;
    char *last_name;
    int age;
} Person;

Swift

typealias getPersonFunc = @convention(c) () -> UnsafeMutablePointer<Person>
typealias freePersonFunc = @convention(c) (UnsafeMutablePointer<Person>) -> Void

...

let handle = dlopen("libsimple.dylib", RTLD_LOCAL|RTLD_NOW)
let get_person_sym = dlsym(handle, "get_person")
let getPerson = unsafeBitCast(get_person_sym, to: getPersonFunc.self)
let cPerson = getPerson()
let person = cPerson.withMemoryRebound(to: Person.self, capacity: 1) { $0.pointee }
let firstName = String(cString: UnsafeRawPointer(person.first_name).assumingMemoryBound(to: CChar.self))
let lastName = String(cString: UnsafeRawPointer(person.last_name).assumingMemoryBound(to: CChar.self))

print(firstName)
print(lastName)
print(person.age)

let free_person_sym = dlsym(handle, "free_person")
let freePerson = unsafeBitCast(free_person_sym, to: freePersonFunc.self)
freePerson(cPerson)

dlclose(handle)

Тест

Вывод на консоли отладки для этого примера будет выглядеть следующим образом:

Branford
Marsalis
60

От Swift до C

Предположим, это в. c :

void print_person(Person *person) {
    printf("%s %s is %d years old\n",
           person->first_name,
           person->last_name,
           person->age);
}

Тогда на стороне Swift можно написать:

typealias printPersonFunc = @convention(c) (UnsafeMutablePointer<Person>) -> Void
...
let newPerson = UnsafeMutablePointer<Person>.allocate(capacity: 1)
newPerson.pointee.first_name = UnsafeMutablePointer<Int8>(mutating: ("Norah" as NSString).utf8String)
newPerson.pointee.last_name = UnsafeMutablePointer<Int8>(mutating: ("Jones" as NSString).utf8String)
newPerson.pointee.age = 41
let print_person_sym = dlsym(handle, "print_person")
let printPerson = unsafeBitCast(print_person_sym, to: printPersonFunc.self)
printPerson(newPerson)
newPerson.deallocate()

Это даст следующий вывод на консоль:

Norah Jones is 41 years old
...