2014-11-03 21 views
5

A mają strukturę tak (określone w bson.h z MongoDB c sterownika)uzyskać wskaźnik do tablicy C char Swift

typedef struct 
{ 
    uint32_t domain; 
    uint32_t code; 
    char message[504]; 
} bson_error_t; 

Swift, że posiada wskaźnik do tej struktury, jak poniżej:

err: UnsafePointer<bson_error_t> = ... 

teraz cokolwiek robię, nie można przekonwertować message[504] (który Swift widzi jako krotki (int8, int8, int8 ... 504 razy)) w celu char* go używać w String.fromCString(). Czy to możliwe w Swift? Jako rozwiązanie tymczasowe utworzyłem pomocniczą funkcję C w oddzielnym pliku .c, który pobiera err *bson_error_t i zwraca char*, ale to jest dziwne, jeśli Swift nie może zrobić tego samodzielnie.

+0

mam wrażenie łączą tablice z gigantycznymi friggin-krotkami, ponieważ dostęp ma znaczenie znacznie więcej niż kopiowanie tego materiału jako jednej ciągłej tablicy. Każdy sposób, w jaki go przycinasz, wymaga powtórzenia tego i przekazania go do prawidłowej pamięci, więc funkcja C, tak jak lub nie, jest najlepsza. – CodaFi

+0

No cóż, nie widzę żadnego punktu w konwersji tablicy char C (lub jakiejkolwiek tablicy C) na krotkę ze względu na dostępność. Tablice są tablicami, a krotki krotkami. Nie pamiętam przypadku, w którym użyłem tablicy do uzyskiwania dostępu do elementów z twardymi indeksami. W tym celu istnieją krotki i struktury, a nie tablice. – Uniqus

Odpowiedz

1

Oto moja propozycja (podobny do Rintaro na podejście, może nieco prostsze):

var err: UnsafeMutablePointer<bson_error_t> = ... 

var msg = err.memory.message 
let msgString = withUnsafePointer(&msg) { String.fromCString(UnsafePointer($0)) } 
println(msgString) 
+0

Dziękuję. Wybrałem twoją odpowiedź, ponieważ jest najkrótsza. Próbowałem zrobić to samo, ale bez pośredniego 'var msg', i nie skompilowałem go po prostu' & err.memory.message'. – Uniqus

3

To nie jest ładne, nie intuicyjne, ale jest wykonalne. Tylko w Swift, kod C kleju nie jest potrzebny. Minimalny demo:

B.H.

typedef struct { 
    int n; 
    char s[8]; 
} Bridged; 

Bridged *make_b(void); 

b.c

#include <stdlib.h> 
#include <string.h> 
#include "b.h" 

Bridged *make_b(void) 
{ 
    Bridged *p = calloc(sizeof(*p), 1); 
    memcpy(p->s, "foobarz", 8); 
    return p; 
} 

b.swift:

// half compile-time, half run-time black magic 
func toCharArray<T>(t: T) -> [CChar] { 
    var a: [CChar] = [] 
    let mirror = reflect(t) 
    for i in 0 ..< mirror.count { 
     a.append(mirror[i].1.value as CChar) 
    } 
    return a 
} 

let b = make_b().memory.s  // bridged tuple of 8 chars 
let a = toCharArray(b)  // Swift array of (8) CChars 
let s = String.fromCString(a) // proper Swift string 

println(s) 

kompilacji:

$ xcrun swiftc -O -c b.swift -import-objc-header b.h 
$ clang -O2 -c b.c -o b.c.o 
$ xcrun swiftc b.o b.c.o -o b 

Run:

$ ./b 
Optional("foobarz") 
0

Szybki sposób odzyskać wiadomość String z bson_error_t:

extension bson_error_t { 
    mutating func messageString() -> String? { 
     return String.fromCString(
      { (p:UnsafePointer<Void>) in UnsafePointer<CChar>(p) }(&self.message.0) 
     ) 
    } 
} 

// Usage: 
var err: UnsafeMutablePointer<bson_error_t> = ... 
... 
let errMessage = err.memory.messageString()