过去几天我一直在同一条船上。我最终提出了一个通用方案来处理来自 C API 的 C 结构中的 C 数组,如果必须处理大型数组,那很好,但它必须使用“unsafeBitCast()”。它还必须适用于每个固定的 C 数组。这是回答当前问题的改编(代码已经过测试并且正在运行):
// This is our C array in this case char[8]
typealias CArray8Chars = (
CChar, CChar, CChar, CChar, CChar, CChar, CChar, CChar
)
let zero8Chars: CArray8Chars = (
0, 0, 0, 0, 0, 0, 0, 0
)
struct CString8 {
private var value: CArray8Chars = zero8Chars
var asString: String {
mutating get {
var cString = [CChar]()
for i in 0..<sizeofValue(value) {
cString += [self[i]]
if self[i] == 0 {
break
}
}
return String.fromCStringRepairingIllFormedUTF8(&cString).0!
}
set {
let cchars = Array(newValue.utf8).map { CChar(Int8(bitPattern: UInt8($0))) }
for i in 0..<min(cchars.count,sizeof(CArray8Chars))-1 { self[i] = cchars[i] }
self[min(cchars.count,sizeof(CArray8Chars))-1] = 0
}
}
subscript(i: Int) -> CChar {
mutating get {
let bytePtr = withUnsafePointer(&value, { (ptr) -> UnsafePointer<CChar> in
return unsafeBitCast(ptr, UnsafePointer<CChar>.self)
})
return bytePtr[i]
}
set {
let bytePtr = withUnsafeMutablePointer(&value, { (ptr) -> UnsafeMutablePointer<CChar> in
return unsafeBitCast(ptr, UnsafeMutablePointer<CChar>.self)
})
bytePtr[i] = newValue
}
}
}
现在,对于摩托车 C 结构,它将如下所示:
struct MotorCycle {
var mfg = CString8()
var model = CString8()
}
var cycle = MotorCycle()
GetMotorcycle(&cycle)
var manufacturer = cycle.mfg.asString // Since the string comes from C it works fine
这也允许使用 Unicode 字符串设置 mfg/model,但需要注意:
// "?" utf8 encoding makes the C string too big, so it gets cut. What's left represents an unknown char
cycle.model.asString = "I do ? Motor Bikes"
println(cycle.model.asString)
并使元组可索引:
println(cycle.mfg[2])
cycle.model[2] = 32 // space. They are CChars, thus Int8
如果喜欢 CString8 可以进一步扩展,允许获取/设置子字符串等。但这超出了这个问题的范围。