Swift中String与CChar数组的转换
在现阶段Swift的编码中,我们还是有很多场景需要调⽤⼀些C函数。在Swift与C的混编中,经常遇到的⼀个问题就是需要在两者中互相转换字符串。在C语⾔中,字符串通常是⽤⼀个char数组来表⽰,在Swift中,是⽤CChar数组来表⽰。从CChar的定义可以看到,其实际上是⼀个Int8类型,如下所⽰:
1 2 3 4 5/// The C 'char' type.
///
/// This will be the same as either `CSignedChar` (in the common /// case) or `CUnsignedChar`, depending on the platform.
public typealias CChar = Int8
如果我们想将⼀个String转换成⼀个CChar数组,则可以使⽤String的cStringUsingEncoding⽅法,它是String扩展中的⼀个⽅法,其声明如下:
1 2 3 4/// Returns a representation of the `String` as a C string
/// using a given encoding.
@warn_unused_result
public func cStringUsingEncoding(encoding: NSStringEncoding) -> [CChar]?
参数指定的是编码格式,我们⼀般指定为NSUTF8StringEncoding,因此下⾯这段代码:
1 2 3let str: String = "abc1个"
// String转换为CChar数组
let charArray: [CChar] = str.cStringUsingEncoding(NSUTF8StringEncoding)!
其输出结果是:
swift 字符串转数组
1[97, 98, 99, 49, -28, -72, -86, 0]
可以看到"个"字由三个字节表⽰,这是因为Swift的字符串是Unicode编码格式,⼀个字符可能由1个或多个字节组成。另外需要注意的是CChar数组的最后⼀个元素是0,它表⽰的是⼀个字符串结束标志符\n。
我们知道,在C语⾔中,⼀个数组还可以使⽤指针来表⽰,所以字符串也可以⽤char *来表⽰。在Swift中,指针是使⽤UnsafePointer或UnsafeMutablePointer来包装的,因此,char指针可以表⽰为UnsafeP
ointer,不过它与[CChar]是两个不同的类型,所以以下代码会报编译器错误:
1 2// Error: Cannot convert value of type '[CChar]' to specified type 'UnsafePointer'
let charArray2: UnsafePointer = str.cStringUsingEncoding(NSUTF8StringEncoding)!
不过有意思的是我们可以直接将String字符串传递给带有UnsafePointer参数的函数或⽅法,如以下代码所⽰:
1 2 3 4 5func length(s: UnsafePointer) {    print(strlen(s))
}
length(str)
// 输出:7\n
⽽String字符串却不能传递给带有[CChar]参数的函数或⽅法,如以下代码会报错误:
1 2 3 4 5func length2(s: [CChar]) {
print(strlen(s))
}
// Error: Cannot convert value of type 'String' to expected argument type '[CChar]' length2(str)
实际上,在C语⾔中,我们在使⽤数组参数时,很少以数组的形式来定义参数,则⼤多是通过指针⽅式来定义数组参数。如果想从[CChar]数组中获取⼀上String字符串,则可以使⽤String的fromCString⽅法,其声明如下:
1 2 3 4 5 6 7/// Creates a new `String` by copying the nul-terminated UTF-8 data /// referenced by a `CString`.
///
/// Returns `nil` if the `CString` is `NULL` or if it contains ill-formed /// UTF-8 code unit sequences.
@warn_unused_result
public static func fromCString(cs: UnsafePointer) -> String?
从注释可以看到,它会将UTF-8数据拷贝以新字符串中。如下⽰例:
1 2let chars: [CChar] = [99, 100, 101, 0]
let str2: String = String.fromCString(chars)!
2 3let str2: String = String.fromCString(chars)! // 输出:cde
这⾥需要注意的⼀个问题是,CChar数组必须以0结束,否则会有不可预料的结果。在我的Playground⽰例代码中,如果没有0,报了以下错误:
1Execution was interrupted. reason: EXC_BAD_INSTRUCTION
还有可能出现的情况是CChar数组的存储区域正好覆盖了之前某⼀对象的区域,这⼀对象有⼀个可以表⽰字符串结尾的标识位,则这时
候,str2输出的可能是"cde1⼀"。
⼩结
在Swift中,String是由独⽴编码的Unicode字符组成的,即Character。⼀个Character可能包括⼀个或多个字节。所以将String字符串转换成C语⾔的char *时,数组元素的个数与String字符的个数不⼀定相同(
即在Swift中,与unt计算出来的值不⼀定相等)。这⼀点需要注意。另外还需要注意的就是将CChar数组转换为String时,数组最后⼀个元素应当为字符串结束标志符,即0。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。