Struct 将结构中的C字符串转换为Swift字符串

Struct 将结构中的C字符串转换为Swift字符串,struct,tuples,swift,Struct,Tuples,Swift,我正在Swift应用程序中使用现有的C库,并尝试将C字符缓冲区转换为Swift字符串 桥接 typedef struct { char mfg[8]; char model[8]; } motorcycle; void GetMotorcycle(motorcycle *m); 斯威夫特 var cycle = motorcycle(mfg: (0,0,0,0,0,0,0,0), model: (0,0,0,0,0,0,0,0)); GetMotorcycle(&cycle) var

我正在Swift应用程序中使用现有的C库,并尝试将C字符缓冲区转换为Swift字符串

桥接

typedef struct { char mfg[8]; char model[8]; } motorcycle;

void GetMotorcycle(motorcycle *m);
斯威夫特

var cycle = motorcycle(mfg: (0,0,0,0,0,0,0,0), model: (0,0,0,0,0,0,0,0));
GetMotorcycle(&cycle)
var manufacturer : String = String.fromCString(cycle.mfg)     // Error
这会产生“找不到接受提供的参数的'fromCString'的重载”


由于Swift将C字符数组视为元组,因此我无法找到将其转换为Swift字符串的方法。

好吧,至少该C字符数组只有八个字符长,因为目前无法迭代元组。以下是如何转换它:

func char8ToString(tuple: (CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar)) -> String {
    let arr: unichar[] = [unichar(tuple.0), unichar(tuple.1),
                        unichar(tuple.2), unichar(tuple.3),
                        unichar(tuple.4), unichar(tuple.5),
                        unichar(tuple.6), unichar(tuple.7)]
    let len = arr.reduce(0) { $1 != 0 ? $0 + 1 : $0 }
    return NSString(characters: arr, length: len)
}

var manufacturer: String = char8ToString(cycle.mfg)

希望我们能尽快获得语言支持,以便更好地处理此案例

过去几天我一直在同一条船上。我最终从C API中提出了一个在C结构中处理C数组的通用方案,如果必须处理大型数组,这很好,但它必须使用“unsafeBitCast()”。此外,它还必须适用于每个固定C阵列。这是回答当前问题的改编(代码已经过测试,并且正在运行):

这也允许使用Unicode字符串设置mfg/模型,但需要注意:

// "Swift's built-in 
reflect()
and
MirrorType
are pretty neat and allow us to inspect the tuple, determine its length, and iterate over its contents.

let tuple = (100, 120, 49, 100)
let mirror = reflect(tuple)

var string = String()
for index in 0..<mirror.count {
    let value = mirror[index].1.value as! Int
    let character = UnicodeScalar(value)
    string.append(character)
}

println(string) // prints "dx1d"

/“Swift的内置
reflect()
MirrorType
非常简洁,允许我们检查元组,确定其长度,并迭代其内容

func tuple2string<T>(tuple: T) -> String {
    var result = Array<CChar>()
    let mirror = Mirror(reflecting: tuple)
    for child in mirror.children {
        if let value = child.value as? CChar {
            result.append(value)
        }
    }
    result.append(CChar(0))  // Null terminate

    return String.fromCString(result) ?? ""
}
let tuple=(10012049100)
让镜像=反射(元组)
var string=string()

对于0..中的索引,这里有一个适用于swift 2.1的类型安全解决方案

String(cString: UnsafeRawPointer([myTuple]).assumingMemoryBound(to: CChar.self))
func tuple2string(tuple:T)->String{
var result=Array()
让镜像=镜像(反射:元组)
给镜子里的孩子{
如果let value=child.value as?CChar{
result.append(值)
}
}
result.append(CChar(0))//Null终止
返回字符串.fromCString(结果)?“”
}
但是,对于较大的数组,这是非常缓慢的,因为它需要检查每个字符的类型,因为编译器无法知道传入的元组都是相同的类型。

swift 3:

func stringFromCString(tupleOfBytes: (CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar)) -> String {
    var bytes = tupleOfBytes
    let string = withUnsafePointer(to: &bytes) { ptr -> String in
        return String(cString: UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self))
    }
    return string
}

以下是由Swift 3Swift 4支持的解决方案

let string = withUnsafePointer(to: &tupleOfBytes) { ptr -> String in
    return String(cString: UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self))
}
return string
或者,如果您想将行内函数用作具有字节元组的函数,请尝试以下方法

extension String {
    init<T>(tupleOfCChars: T, length: Int = Int.max) {
        self = withUnsafePointer(to: tupleOfCChars) {
            let lengthOfTuple = MemoryLayout<T>.size / MemoryLayout<CChar>.size
            return $0.withMemoryRebound(to: UInt8.self, capacity: lengthOfTuple) {
                String(bytes: UnsafeBufferPointer(start: $0, count: Swift.min(length, lengthOfTuple)), encoding: .utf8)!
            }
        }
    }
}

Swift 5.2-此解决方案可以接受任意长度的元组,不进行任何额外复制,并使用最新的安全内存绑定约定

扩展字符串{
init(tupleOfchars:T,长度:Int=Int.max){
self=withUnsafePointer(指向:tupleOfchars){
让lengthOfTuple=MemoryLayout.size/MemoryLayout.size
返回$0.withMemoryRebound(收件人:UInt8.self,容量:lengthOfTuple){
字符串(字节:UnsafeBufferPointer(开始:$0,计数:Swift.min(长度,长度为整数)),编码:.utf8)!
}
}
}
}

char8ToString()生成的字符串后面有0个字符。假设mfg=BMW,model=K1200S,此NSLog语句:NSLog(“mfg=(char8ToString(cycle.mfg)),model=(char8ToString(cycle.model)))生成:“mfg=BMW“谢谢--更新了我的答案以删除尾随的空字符。显然,您可以按如下所述迭代元组:
let string = withUnsafePointer(to: &tupleOfBytes) { ptr -> String in
    return String(cString: UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self))
}
return string
extension String {
    init<T>(tupleOfCChars: T, length: Int = Int.max) {
        self = withUnsafePointer(to: tupleOfCChars) {
            let lengthOfTuple = MemoryLayout<T>.size / MemoryLayout<CChar>.size
            return $0.withMemoryRebound(to: UInt8.self, capacity: lengthOfTuple) {
                String(bytes: UnsafeBufferPointer(start: $0, count: Swift.min(length, lengthOfTuple)), encoding: .utf8)!
            }
        }
    }
}