为什么String' s字节:和cString:initializers在这里给出不同的结果?

时间:2017-06-15 14:38:40

标签: swift string

将字节转换为字符串非常常见......

import Foundation

var data = Data(bytes: [65,66,67,0,0,0,0,0,0])
let str0 = String(bytes: data, encoding: .utf8)

let str1 = data.withUnsafeBytes { (p: UnsafePointer<CChar>)->String? in
    return String(cString: p, encoding: .utf8)
}

比较字符串

print(str0 == str1) // false   ??????????

对我来说有点不合理。

下一个片段解释了为什么字符串不同

print(str0 as Any, str0 ?? "", str0?.characters.count as Any)
print(str1 as Any, str1 ?? "", str1?.characters.count as Any)

打印

Optional("ABC\0\0\0\0\0\0") ABC Optional(9)
Optional("ABC") ABC Optional(3)

预计会出现这种情况吗?

一见钟情,我理解了Rob的回答,但是......

let str2 = data.withUnsafeBytes { (p: UnsafePointer<Int8>)->String? in
    return String(utf8String: p)
}

给了我3个字符长的字符串。是的我知道CChar是Int8的类型,但这意味着,p代表CString自动吗?

最后,我在IBM Sandbox中检查了相同的 http://swift.sandbox.bluemix.net/#/repl/5942a7d7c0be7f183ad81525

在这两种情况下,生成的字符串都相同,包含3个字符

enter image description here

1 个答案:

答案 0 :(得分:2)

是的,这种行为是预期的。

C语言及其标准库支持的字符串由ASCII NUL终止,字节值为零,并且没有明确的长度。所以C字符串不能包含NUL。

但是在Swift(以及许多其他语言)中,每个字符串都存储有一个长度,因此它可以在字符串中的任何位置包含任意数量的NUL。

您从str0创建了Data,而Data也有一个长度。因此,您用于str0的初始化程序可以创建包含NUL的字符串。但是你使用str1初始化器创建了init(cString:encoding:),它特别指出输入是一个C字符串,它由第一个NUL终止。所以str1不能包含任何NUL。