Строковое значение для поведения параметра функции UnsafePointer<UInt8>

Я нашел следующий код компилируется и работает:

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 今日

Насколько я знаю, это недокументированное поведение. из документа:

Когда функция объявлена ​​как принимающая аргумент UnsafePointer, она может принять любое из следующего:

  • ноль, который передается как нулевой указатель
  • Значение UnsafePointer, UnsafeMutablePointer или AutoreleasingUnsafeMutablePointer, которое при необходимости преобразуется в UnsafePointer.
  • Выражение in-out, операндом которого является lvalue типа Type, который передается как адрес lvalue
  • Значение [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 今日
}

1 ответ

Решение

Это работает из-за одного из изменений совместимости, которые команда Swift внесла с момента первого запуска - вы правы, похоже, что он еще не вошел в документацию. String работает там, где UnsafePointer<UInt8> требуется, чтобы вы могли вызывать функции C, которые ожидают const char * Параметр без лишней работы.

Посмотрите на функцию C strlen, определенный в "shims.h":

size_t strlen(const char *s);

В Swift это выглядит так:

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

Который можно назвать с String без дополнительной работы:

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

Посмотрите на изменения в этом ответе, чтобы увидеть, как взаимодействие C-строки изменилось с течением времени: /questions/20901853/rabota-so-strokami-c-v-swift-ili-kak-preobrazovat-unsafepointercchar-v-cstring/20901858#20901858

Другие вопросы по тегам