【问题标题】:Why does String's bytes: and cString: initializers give different results here?为什么 String 的 bytes: 和 cString: 初始化器在这里给出不同的结果?
【发布时间】:2017-06-15 14:38:39
【问题描述】:

将字节转换为字符串是很常见的......

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   ??????????

对我来说有点意外。

下一个sn-p解释,为什么字符串不一样

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 个字符

【问题讨论】:

    标签: swift string


    【解决方案1】:

    是的,这是正常现象。

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

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

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

    【讨论】:

    • 我不知道“它可以在任何地方包含任意数量的 NUL”,我必须检查我的其余代码 :-) 谢谢!
    • 那么 String(utf8String: p) 呢?它给了我与 String(cString: p, encoding: .utf8) (3 characters) 相同的结果
    • docs hereinit?(utf8String: UnsafePointer&lt;CChar&gt;)“生成一个字符串,该字符串是通过从给定的 UTF8 编码字节的 C 数组复制数据而创建的。”。所以这个初始化器也假设一个 C 字符串。
    • String(utf8String:) 也将 C 字符串作为输入并在第一个 NUL 处停止。
    • @user3441734: String(uft8String:) 只接受一个指针作为参数,没有计数。如果直到空终止,它应该如何确定要读取多少字节?
    猜你喜欢
    • 1970-01-01
    • 2016-12-30
    • 1970-01-01
    • 2015-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    相关资源
    最近更新 更多