2016-04-22 10 views
0

Ich habe Probleme eine Reihe von Swift-Strings in einem Array für AC-Funktion mit der Signatur umzuwandeln:Array of Swift-Strings in const char * const *

PGconn *PQconnectStartParams(const char * const *keywords, const char * const *values, int expand_dbname) 

In Swift, die const char * const * zeigt sich als:

<UnsafePointer<UnsafePointer<Int8>> 

Also versuche ich, den Inhalt eines Dictionary zu konvertieren [String: String] genannt ‚Optionen‘ und Futtermittel, die an die Funktion wie folgt:

var keys = [[Int8]]() 
var values = [[Int8]]() 
for (key, value) in options { 
    var int8Array = key.cStringUsingEncoding(NSUTF8StringEncoding)! 
    keys.append(int8Array) 
    int8Array = value.cStringUsingEncoding(NSUTF8StringEncoding)! 
      values.append(int8Array) 
} 
pgConnection = PQconnectStartParams(UnsafePointer(keys), UnsafePointer(values), 0) 

Es kompiliert und läuft, aber die Funktion funktioniert nicht.

Jeder Einblick würde sehr geschätzt werden.

+0

Ok sofort: Sie sprechen eine Funktion mit dem Namen 'PQconnectdbParams()' noch Sie rufen eine Funktion namens 'PQconnectStartParams() '...? – RastaJedi

+0

Werfen Sie einen Blick auf 'const char * const * keywords'. 'keywords' ist ein Zeiger auf einen' const' Zeiger auf ein 'const char' (das ist das gleiche wie' char const', beide bedeuten "Konstanten"). Das bedeutet, dass Sie nicht nach einer einzelnen Zeichenkette suchen ("null terminated character array"), aber Sie suchen wahrscheinlich nach einem * Array * von Zeichenketten. Irgendwie wie 'char ** argv'. Ich weiß nicht viel über Swift, aber Sie müssten herausfinden, wie man eine Swift-Zeichenkette in ein C-null-terminiertes Zeichen-Array konvertiert und dann herausfinden muss, wie man ein Array von diesen in ein C-Array von konvertieren kann Saiten, denke ich. – RastaJedi

+0

Entschuldigung. Clerical Fehler. Guckte auf den falschen Teil der Dokumentation. Die Funktionssignatur wurde korrigiert und du hast recht, ich suche kein Null-terminiertes Array. Ich brauche und Array von Cstrings. Was ich dachte, dass ich in meinem Code erzeugte. – user5892643

Antwort

3

Das ist nicht perfekt, aber zumindest funktioniert es.

let options = ["key1": "value1", "key2": "value2", "key3": "value3", "key4": "value4"] 

var keys = [String]() 

for (key, value) in options { 

    keys.append(key) 
} 

//you need to identify how many paramenters should be provided and set them following "static way" 
//I did not find how to prepare this dynamically 
let cKey1 = keys[0].cStringUsingEncoding(String.defaultCStringEncoding())! 
let key1Pointer = UnsafePointer<CChar>(cKey1) 

let cKey2 = keys[1].cStringUsingEncoding(String.defaultCStringEncoding())! 
let key2Pointer = UnsafePointer<CChar>(cKey2) 

let cKey3 = keys[2].cStringUsingEncoding(String.defaultCStringEncoding())! 
let key3Pointer = UnsafePointer<CChar>(cKey3) 

let cKey4 = keys[3].cStringUsingEncoding(String.defaultCStringEncoding())! 
let key4Pointer = UnsafePointer<CChar>(cKey4) 


let keysCArray = [key1Pointer, key2Pointer, key3Pointer, key4Pointer] 

f(keysCArray) 

/* 
C - code 

void f(const char * const *keywords) { 

printf("%s\n", keywords[0]); 
printf("%s\n", keywords[1]); 
printf("%s\n", keywords[2]); 
printf("%s\n", keywords[3]); 

} 
*/ 

Ich hoffe, es hilft. Ich kann meine Beispiel-App teilen, wenn Sie möchten.

+1

Danke Melifaro. Ich habe diesen Ansatz bereits versucht, bevor ich die Frage gepostet habe, aber ich habe weiterhin EXC_BAD_ACCESS erhalten. Also dachte ich, dass der Ansatz falsch war. Aber Ihr Punkt über das Identifizieren, wie viele Parameter mir klargemacht haben, dass die Arrays null-terminiert sein müssen. Also habe ich jedem Array einen UnsafePointer (null) hinzugefügt und alles funktioniert jetzt. Danke für das Einschalten meiner Glühbirne! – user5892643

+1

Schönes finden! Danke für die Rückmeldung. –

0

Hier ist eine Erweiterung Array in swift3, dass es allgemein tun:

public extension Array { 

    // Translate [String] to (const char * const *), which translates to Swift as 
    public func cStringArray() throws -> ArrayBridge<Element,CChar> { 
     return try ArrayBridge<Element,CChar>(array:self) { 
      guard let item = $0 as? String, 
        let translated = item.cString(using: .utf8) else { 
       fatalError() 
      } 
      return translated 
     } 
    } 
} 

/* 
We need to have this intermediate object around to hold on to the translated objects, otherwise they will go away. 
The UnsafePointer won't hold on to the objects that it's pointing to. 
*/ 
public struct ArrayBridge<SwiftType,CType> { 

    let originals :[SwiftType] 
    let translated :[[CType]] 
    let pointers :[UnsafePointer<CType>?] 
    public let pointer :UnsafePointer<UnsafePointer<CType>?> 

    init(array :[SwiftType], transform: @noescape (SwiftType) throws -> [CType]) throws { 
     self.originals = array 
     self.translated = try array.map(transform) 

     var pointers = [UnsafePointer<CType>?]() 
     for item in translated { 
      pointers.append(UnsafePointer<CType>(item)) 
     } 
     pointers.append(nil) 
     self.pointers = pointers 
     self.pointer = UnsafePointer(self.pointers) 
    } 
} 

Dann können Sie den richtigen C-kompatiblen Zeiger erhalten, indem

tun
try stringArray.cStringArray().pointer 
Verwandte Themen