Передайте Swift uuid_t функции C

Как с помощью Swift передать UUID функции C, которая принимает uuid_t?

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

bool my_set_uuid(uuid_t uuid);

И в Swift я пытаюсь передать ему новый UUID:

let uuid = UUID()
my_set_uuid(uuid.uuid)

Я получаю следующую ошибку: «Невозможно преобразовать значение типа 'uuid_t' (aka '(UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8 ) ') к ожидаемому типу аргумента' UnsafeMutablePointer! '"

Я знаю, что это потому, что UUID.uuid имеет тип uuid_t, который реализован как массив C из 16 байтов, который становится кортежем из 16 UInt8 в Swift. Но почему я не могу передать C uuid_t в C? Вроде ожидает указателя.

Итак, я пытаюсь создать указатель на свой uuid с помощью withUnsafeMutableBytes. Я обнаружил, что это сработало:

let _: UInt8 = withUnsafeMutablePointer(to: &uuid.0) { ptr in
    my_set_uuid(ptr)
    return 0
}

Но я также читал, что & uuid.0 небезопасно, потому что я использую весь кортеж (как массив) в своей функции C. Кроме того, все переодевания, которые мне приходилось делать с let _: UInt8 и return 0, кажется неправильным.


person craig65535    schedule 24.07.2017    source источник


Ответы (2)


Действительно небезопасно использовать &uuid.0 таким образом. Поскольку компилятор Swift может создать копию единственного элемента во временной области и передать адрес этой области функции. Этого может не происходить в оптимизированном коде, но вы не можете предсказать, какой код генерирует Swift.

Чтобы сделать ваш код безопасным, вам может потребоваться написать что-то вроде этого:

    let uuid = UUID()
    var rawUuid = uuid.uuid
    // (You can rewrite the two lines above into a sigle line as `var rawUuid = UUID().uuid`
    let result = withUnsafeMutablePointer(to: &rawUuid) {uuidPtr in
        uuidPtr.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<uuid_t>.size) {bytePtr in
            my_set_uuid(bytePtr)
        }
    }

(result получает значение my_set_uuid(bytePtr). Если вы хотите проигнорировать результат, замените let result на _.)

uuid_t - это тип массива фиксированного размера в C, с которым сложно работать в Swift. Возможно, у типа кортежа в Swift должны быть лучшие способы обработки таких случаев использования.

person OOPer    schedule 25.07.2017

Вы можете попробовать это:

    let uuid = UUID().uuidString        
    _ = uuid.withCString { s1 in
        my_set_uuid(UnsafeMutablePointer(mutating: s1))
    }
person Codus    schedule 25.07.2017
comment
Я хочу передать 16 байтов UUID, а не UUID в виде строки. - person craig65535; 25.07.2017
comment
поэтому используйте UnsafeMutablePointer(mutating: s1) для передачи 16 байтов - person Codus; 25.07.2017
comment
Объясните, пожалуйста, как - person craig65535; 25.07.2017