关于swift:UnsafePointer 函数参数行为的字符串值

String value to UnsafePointer function parameter behavior

我发现以下代码可以编译并运行:

1
2
3
4
5
6
7
8
9
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,这是今日的有效UTF8表示形式

据我所知,这是未记录的行为。 从文档中:

When a function is declared as taking a UnsafePointer argument, it can accept any of the following:

  • nil, which is passed as a null pointer
  • An UnsafePointer, UnsafeMutablePointer, or AutoreleasingUnsafeMutablePointer value, which is converted to UnsafePointer if necessary
  • An in-out expression whose operand is an lvalue of type Type, which is passed as the address of the lvalue
  • A [Type] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call

在这种情况下,str不在其中。

我想念什么吗?

添加:

如果参数类型为UnsafePointer,则不起作用

1
2
3
4
5
6
7
8
9
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

1
2
3
4
5
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 今日
}


之所以如此,是因为Swift团队自首次发布以来就进行了互操作性更改-您说对了,看来它还没有纳入文档范围。 String在需要UnsafePointer的地方工作,因此您可以调用需要const char *参数的C函数,而无需进行大量额外工作。

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

1
size_t strlen(const char *s);

在Swift中,它是这样实现的:

1
func strlen(s: UnsafePointer<Int8>) -> UInt

可以用String调用而无需其他工作:

1
2
3
let str ="Hi."
strlen(str)
// 3

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