2014-11-03 42 views
5

A具有這樣的結構(在mongodb的C驅動的bson.h定義):獲取一個指向一個C char數組中夫特

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

在夫特我有一個指針指向這個結構是這樣的:

err: UnsafePointer<bson_error_t> = ... 

現在,無論我做什麼,我不能轉換message[504](斯威夫特認爲的(INT8,INT8,INT8的元組,... 504倍)),以char*使用它在String.fromCString()。 在Swift中甚至有可能這麼做嗎?作爲臨時解決方案,我在單獨的.c文件中創建了一個輔助函數C函數,該文件需要err *bson_error_t並返回char*,但是如果 Swift無法自行完成,則這很奇怪。

+0

給我的感覺他們將數組連接到巨大的元組,因爲訪問的重要性遠遠超過將這些東西作爲一個連續數組複製出來。無論你如何切割它,你都需要遍歷它並將其編組到合適的mallocated內存中,所以C函數,不管你喜歡與否,都是你最好的選擇。 – CodaFi 2014-11-03 06:42:33

+0

嗯,我沒有看到任何將C char數組(或任何C數組)轉換爲元組的可訪問性。數組是數組,元組是元組。當我使用數組訪問具有硬編碼索引的元素時,我不記得一個例子。爲此,元組和結構確實存在,而不是數組。 – Uniqus 2014-11-03 11:20:09

回答

1

這裏我的建議(類似於林太郎的做法,或許稍微簡單一些):

var err: UnsafeMutablePointer<bson_error_t> = ... 

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

謝謝。我選擇了你的答案,因爲它是最短的答案。我試圖做同樣的事情,但沒有中間'''''''''msg',並且它只用'&err.memory.message'編譯。 – Uniqus 2014-11-03 11:05:56

3

這不美觀,不直觀,但它是可行的。純粹在Swift中,不需要C代碼。一個最小的演示:

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) 

編譯:

$ 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 

運行:

$ ./b 
Optional("foobarz") 
0

快速的黑客攻擊,從bson_error_t檢索消息String

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()