Mit Swift können Sie vorhandene C-Bibliotheksaufrufe und Systemaufrufe normal aufrufen. Dies ist aus der Sicht der Verwendung früherer Assets richtig, aber da Swift typenstrenger als C ist, ist es nicht ungewöhnlich, dass Probleme beim Aufrufen von C-Funktionen auftreten.
Dieses Mal habe ich das dritte Argument start_routine
von pthread_create
von der C-Funktion bis zum Schließen von Swift umgeschrieben. Ich hoffe, es ist hilfreich zu sehen, was mit dem Code passiert, der in C in Swift typisiert wird.
(Da ich ein Anfänger von Swift bin, lassen Sie mich bitte wissen, wenn es Fehler gibt.)
pthread_create
erstellt einen neuen Thread und übergibt den Funktionszeiger der im neuen Thread auszuführenden Funktion mit dem dritten Argument start_routine
. Die Funktionsargumente und Rückgabewerte sind "void *". Wenn Sie also verschiedene Arten von Argumenten und Rückgabewerten verwenden möchten, müssen Sie sowohl für den Aufrufer als auch für den Angerufenen eine Typumwandlung durchführen.
Es ist eine C-ähnliche Idee, etwas "ungültig" zu machen, aber natürlich passt es nicht gut zu Swift.
Dieses Mal wollte ich eine Funktion verwenden, die "int" und "char **" als Argumente verwendet und "int" (kurz gesagt, es ist eine "main" -Funktion) von "pthread_create" zurückgibt, daher habe ich dafür eine Wrapper-Funktion verwendet. Ich habe es in C geschrieben.
void *pthread_main_routine(void *_arg)
{
void **arg = (void **)_arg;
int argc = (int)arg[0];
char **argv = (char**)arg[1];
void *retval = (void *)(long)orig_main(argc, argv);
return retval;
}
Auf der Swift-Seite wurde dies wie folgt genannt.
var thread_arg = [
UnsafeMutablePointer<Void>(bitPattern: args.pointers.count-1),
UnsafeMutablePointer<Void>(args.pointers)
]
pthread_create(&thread, nil, pthread_main_routine, &thread_arg)
Es funktionierte auch im obigen Code, aber aus verschiedenen Gründen habe ich die C-Funktion durch einen Swift-Verschluss ersetzt.
typealias VoidPtr = UnsafeMutablePointer<Void>
typealias VoidPtrArray = [UnsafeMutablePointer<Void>]
typealias CharPtrArray = [UnsafeMutablePointer<CChar>]
let thread_arg = [
unsafeBitCast(args.pointers.count-1, VoidPtr.self),
unsafeBitCast(args.pointers, VoidPtr.self),
]
pthread_create(&thread, nil, {_arg in
let arg = unsafeBitCast(_arg, VoidPtrArray.self)
let argc = Int32(unsafeBitCast(arg[0], Int.self))
let argv = unsafeBitCast(arg[1], CharPtrArray.self)
let retval = unsafeBitCast(Int(orig_main(argc, argv)), VoidPtr.self)
return retval
}, unsafeBitCast(thread_arg, VoidPtr.self))
Ich habe es geschafft, etwas zu machen, das mit viel "unsafeBitCast" funktioniert, aber der Code ist ziemlich langweilig und schwer zu lesen. Code, der in C einfacher zu schreiben ist, sollte in C geschrieben werden.
Beachten Sie übrigens, dass die zu übergebenden Inhalte geringfügig unterschiedlich sind, je nachdem, ob das Swift-Array in den beiden Codes in "void *" oder "char **" in "void *" konvertiert wird.
Die Behandlung von C-Funktionen in Swift2 ist nicht gut, und nur der globale Funktionsname selbst oder das Abschlussliteral können in das dritte Argument dieses pthread_create
eingefügt werden. Wenn Sie einer Variablen eine Funktion zuweisen und diese Variable als Argument angeben, wird wie folgt ein Kompilierungsfehler angezeigt.
A C function pointer can only be formed from a reference to a 'func' or a literal closure
Schreiben Sie auch keinen Code, der von der Umgebung abhängt, auch wenn es sich um ein Abschlussliteral handelt. Wenn Sie beispielsweise innerhalb des Abschlusses auf eine Instanzvariable verweisen, wird ein Kompilierungsfehler angezeigt (siehe unten).
A C function pointer cannot be formed from a closure that captures context
Ich habe das Gefühl, dass dem letzteren nicht geholfen werden kann, aber was ist mit dem ersteren? Ich fühle mich so. Ich hoffe, dass Swift3 hier einfacher zu handhaben ist.