2014-11-03 19 views
5

A hanno una struttura come questa (definito in bson.h del conducente mongodb c):Ottenere un puntatore a una matrice C char a Swift

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

In Swift ho un puntatore a questa struttura come questa:

err: UnsafePointer<bson_error_t> = ... 

Ora, tutto ciò che faccio non posso convertire message[504] (che Swift vede come una tupla di (int8, int8, int8, ... 504 volte)) a char* di utilizzarlo in String.fromCString(). È possibile farlo anche in Swift? Come soluzione temporanea, ho creato una funzione C helper in un file .c separato che prende err *bson_error_t e restituisce char*, ma questo è strano se Swift non può farlo da solo.

+0

ho la sensazione essi collegano gli array alle tuple giganti-giganti perché l'accesso conta molto più della copia di questi elementi come una matrice contigua. In qualunque modo tu lo tagli, avrai bisogno di iterare su questo e metterlo nella giusta memoria mallocated, quindi la funzione C, che ti piaccia o no, è la soluzione migliore. – CodaFi

+0

Bene, non vedo alcun punto nel convertire un array di C char (o qualsiasi array C) in una tupla per l'accessibilità. Gli array sono array, le tuple sono tuple. Non riesco a ricordare un caso quando ho usato un array per accedere a elementi con indici hard-coded. A tale scopo esistono tuple e strutture, non array. – Uniqus

risposta

1

Ecco il mio suggerimento (simile approccio alla Rintaro, forse un po 'più semplice):

var err: UnsafeMutablePointer<bson_error_t> = ... 

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

Grazie. Ho scelto la tua risposta in quanto è la più breve. Ho provato a fare la stessa cosa, ma senza il 'var msg' intermedio, e non è stato compilato con' & err.memory.message'. – Uniqus

3

Non è bello, non è intuitivo, ma è fattibile. Puramente in Swift, non è necessario il codice colla C. Una demo minima:

b.h

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

Bridged *make_b(void); 

a.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) 

Compile:

$ 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

mod rapida per recuperare il messaggio String da 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() 
Problemi correlati