欢迎加入QQ讨论群258996829
赢了现在输了未来 头像
苹果2袋
2
赢了现在输了未来

Swift 中 String 与 CChar 数组的转换

发布时间:2015-10-17 15:03  回复:0  查看:4392   最后回复:2015-10-17 15:03  

在现阶段Swift的编码中,我们还是有很多场景需要调用一些C函数。在Swift与C的混编中,经常遇到的一个问题就是需要在两者中互相转换字符串。在C语言中,字符串通常是用一个char数组来表示,在Swift中,是用CChar数组来表示。从CChar的定义可以看到,其实际上是一个Int8类型,如下所示:

/// 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扩展中的一个方法,其声明如下:

/// Returns a representation of the `String` as a C string
/// using a given encoding.
@warn_unused_result
public func cStringUsingEncoding(encoding: NSStringEncoding) -> [CChar]?
参数指定的是编码格式,我们一般指定为NSUTF8StringEncoding,因此下面这段代码:

let str: String = "abc1个"
// String转换为CChar数组
let charArray: [CChar] = str.cStringUsingEncoding(NSUTF8StringEncoding)!
其输出结果是:

[97, 98, 99, 49, -28, -72, -86, 0]

可以看到"个"字由三个字节表示,这是因为Swift的字符串是Unicode编码格式,一个字符可能由1个或多个字节组成。另外需要注意的是CChar数组的最后一个元素是0,它表示的是一个字符串结束标志符\n。

我们知道,在C语言中,一个数组还可以使用指针来表示,所以字符串也可以用char *来表示。在Swift中,指针是使用UnsafePointer或UnsafeMutablePointer来包装的,因此,char指针可以表示为UnsafePointer,不过它与[CChar]是两个不同的类型,所以以下代码会报编译器错误:

// Error: Cannot convert value of type '[CChar]' to specified type 'UnsafePointer'
let charArray2: UnsafePointer = str.cStringUsingEncoding(NSUTF8StringEncoding)!
不过有意思的是我们可以直接将String字符串传递给带有UnsafePointer参数的函数或方法,如以下代码所示:

func length(s: UnsafePointer) {
    print(strlen(s))
}
length(str)
// 输出:7\n
而String字符串却不能传递给带有[CChar]参数的函数或方法,如以下代码会报错误:

func 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方法,其声明如下:

/// 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数据拷贝以新字符串中。如下示例:

let chars: [CChar] = [99, 100, 101, 0]
let str2: String = String.fromCString(chars)!
// 输出:cde
这里需要注意的一个问题是,CChar数组必须以0结束,否则会有不可预料的结果。在我的Playground示例代码中,如果没有0,报了以下错误:

Execution was interrupted. reason: EXC_BAD_INSTRUCTION

小结

在Swift中,String是由独立编码的Unicode字符组成的,即Character。一个Character可能包括一个或多个字节。所以将String字符串转换成C语言的char *时,数组元素的个数与String字符的个数不一定相同(即在Swift中,与str.characters.count计算出来的值不一定相等)。这一点需要注意。另外还需要注意的就是将CChar数组转换为String时,数组最后一个元素应当为字符串结束标志符,即0。

参考

  1. UTF8String

  2. String Structure Reference

  3. The Swift Programming Language中文版


您还未登录,请先登录

热门帖子

最新帖子