Struct 将结构中的C字符串转换为Swift字符串
我正在Swift应用程序中使用现有的C库,并尝试将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
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 3和Swift 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)!
}
}
}
}