我发现以下代码编译并运行:
func foo(p:UnsafePointer<UInt8>) {
var p = p
for p; p.memory != 0; p++ {
print(String(format:"%2X", p.memory))
}
}
let str:String = "今日"
foo(str)
这会打印E4BB8AE697A5
,这是今日
据我所知,这是无证件行为。来自the document:
当一个函数声明为接受UnsafePointer参数时,它可以接受以下任何一个:
- nil,作为空指针传递
- UnsafePointer,UnsafeMutablePointer或AutoreleasingUnsafeMutablePointer值,必要时转换为UnsafePointer
- 一个输入输出表达式,其操作数是Type类型的左值,它作为左值的地址传递
- 一个[Type]值,作为指向数组开头的指针传递,并在调用期间延长生命周期
在这种情况下,str
不属于他们。
我错过了什么吗?
增加:
如果参数类型为UnsafePointer<UInt16>
func foo(p:UnsafePointer<UInt16>) {
var p = p
for p; p.memory != 0; p++ {
print(String(format:"%4X", p.memory))
}
}
let str:String = "今日"
foo(str)
// ^ 'String' is not convertible to 'UnsafePointer<UInt16>'
即使内部String
表示形式为UTF16
let str = "今日"
var p = UnsafePointer<UInt16>(str._core._baseAddress)
for p; p.memory != 0; p++ {
print(String(format:"%4X", p.memory)) // prints 4ECA65E5 which is UTF16 今日
}
答案 0 :(得分:8)
这是有效的,因为Swift团队自首次推出以来所做的互操作性改变之一 - 你说它看起来还没有进入文档。 String
适用于需要UnsafePointer<UInt8>
的地方,因此您可以调用期望const char *
参数的C函数,而无需额外的工作。
查看“shims.h”中定义的C函数strlen
:
size_t strlen(const char *s);
在Swift中它是这样的:
func strlen(s: UnsafePointer<Int8>) -> UInt
可以使用String
进行调用,无需额外工作:
let str = "Hi."
strlen(str)
// 3
查看此答案的修订版,了解C-string互操作如何随时间变化:https://stackoverflow.com/a/24438698/59541