2015-04-06 17 views
5

Sto provando a interagire con una vecchia applicazione terminale C di Swift. Ho integrato con successo il codice sorgente e ho collegato le intestazioni da C a Swift. Il codice viene compilato e viene eseguito da Xcode 6.3 beta. Ho rinominato punto di ingresso principale dell'app terminale:Come passare un array di stringhe Swift a una funzione C utilizzando un parametro char **

int initialize(int argc, char **argv); 

Tuttavia, sto lottando per passare gli argomenti da Swift a questa funzione C. La mia sfida è convertire gli argomenti nel formato giusto. Tipico input da Swift sarà simile:

let args = ["-c", "1.2.3.4", "-p", "8000"] 

Ho provato scherzi con "cStringUsingEncoding (NSUTF8StringEncoding)" e "withUnsafePointer", ma senza fortuna finora. Qualsiasi aiuto è molto apprezzato!

+0

titolo potrebbe essere "migliore" menzionando che il problema è il parametro char ** in una chiamata di funzione C. –

risposta

6

La funzione C

int initialize(int argc, char **argv); 

viene mappata Swift come

func initialize(argc: Int32, argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>) -> Int32 

Questa è una possibile soluzione:

let args = ["-c", "1.2.3.4", "-p", "8000"] 

// Create [UnsafeMutablePointer<Int8>]: 
var cargs = args.map { strdup($0) } 
// Call C function: 
let result = initialize(Int32(args.count), &cargs) 
// Free the duplicated strings: 
for ptr in cargs { free(ptr) } 

utilizza il fatto che nel strdup($0) stringa Swift $0 viene convertito automaticamente in una stringa C, come spiegato in String value to UnsafePointer<UInt8> function parameter behavior.

+0

Grazie, funziona come un fascino. Per gli altri che cercano di fare qualcosa di simile, dovrei aggiungere che C passa il vettore degli argomenti a partire dall'indice 1 invece di 0. Ho aggiornato i miei argomenti su: let args = ["", "-c", "1.2.3.4", " -p "," 8000 "]. – Mark

+0

Se ho un gioco a riga di comando, pensi che sia possibile eseguirlo e passare argomenti ad esso ed estrarre il suo stdout in un'area di testo, ad esempio in swift? O devo fare il gioco da tutte le parti usando la sua funzione? @Mark – MasterWizard

+0

@AhmedNassar: non è possibile eseguire programmi esterni in iOS, per quanto ne so. –

0

Sulla risposta di Martin, se vi trovate a fare questo molto, si potrebbe avvolgere la parte DUP/libero in una funzione in uno stile simile a String.withCString:

import Darwin 

func withCStrings 
    <R, S: SequenceType where S.Generator.Element == String> 
    (strings: S, @noescape body: (UnsafeBufferPointer<UnsafeMutablePointer<Int8>>) -> R) 
    -> R { 

    let cstrings = map(strings) { strdup($0) } + [nil] 

    let result = cstrings.withUnsafeBufferPointer(body) 

    for ptr in cstrings { free(ptr) } 

    return result 
} 

let execvargs = ["/usr/bin/say"] + dropFirst(Process.arguments) 

let execvresult = withCStrings(execvargs) { 
    execv($0[0], $0.baseAddress) 
}