字符串值为UnsafePointer <UInt8>函数参数行为

rin*_*aro 12 swift

我发现以下代码编译和工作:

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)
Run Code Online (Sandbox Code Playgroud)

这打印E4BB8AE697A5,这是一个有效的UTF8表示??

据我所知,这是无证行为.来自文件:

当函数声明为采用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>'
Run Code Online (Sandbox Code Playgroud)

即使内部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 ??
}
Run Code Online (Sandbox Code Playgroud)

Nat*_*ook 8

这是因为Swift团队自首次发布以来所做的互操作性改变之一 - 你说得对,它看起来还没有进入文档.String适用于UnsafePointer<UInt8>需要的地方,以便您可以调用期望const char *参数的C函数,而无需额外的工作.

查看strlen"shims.h"中定义的C函数:

size_t strlen(const char *s);
Run Code Online (Sandbox Code Playgroud)

在Swift中它通过以下方式实现:

func strlen(s: UnsafePointer<Int8>) -> UInt
Run Code Online (Sandbox Code Playgroud)

可以使用a进行调用String,无需额外工作:

let str = "Hi."
strlen(str)
// 3
Run Code Online (Sandbox Code Playgroud)

查看此答案的修订版,了解C-string互操作如何随时间变化:https://stackoverflow.com/a/24438698/59541