1

У меня есть массив с плавающей запятой (floatArray), идущий из файла HDF5, и я бы хотел использовать эти данные в качестве входных данных для функции, которая принимает Unsafe [Mutable] Pointer (inputForFunction). Я новичок в UnsafePointer, поэтому мне нужна чья-то помощь.Как преобразовать UnsafePointer <[Float]> или поместить данные Float Array в Unsafe [Mutable] Pointer <Float> в Swift 3?

Один из способов я имею в виду, чтобы сохранить массив в файл, а затем открыть его и отобразить дескриптор файла в памяти переменной для ввода функции:

// read the data from HDF5 file 
    var floatArray: [Float] = try originalHDF5DataSet.read() 

    // store the data 
    let dataToStore = NSData(bytes: &floatArray, length: sizeOfArray * MemoryLayout<Float>.size) 
    let tmpPath = URL(fileURLWithPath: NSTemporaryDirectory()) 
    let filePath = tmpPath.appendingPathComponent("floatArrayData").appendingPathExtension("dat") 
    do{ 
    try data.write(to: filePath, options: .atomic) 
    let fileManager : FileManager = FileManager.default 
    if fileManager.fileExists(atPath:filePath.path){ 
     print("Success") 
    }else{ 
     print("Fail") 
    } 

    // open the data 
    let dataPath = filePath.path 
    let fd = open(dataPath, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) 
    assert(fd != -1, "Error: failed to open output file at \""+dataPath+"\" errno = \(errno)\n") 
    // memory map the parameters 
    let hdr = mmap(nil, Int(sizeOfArray), PROT_READ, MAP_FILE | MAP_SHARED, fd, 0) 
    // cast Void pointers to Float 
    let inputForFunction = UnsafePointer<Float>(hdr!.assumingMemoryBound(to: Float.self)) 
    } catch{ 
    print("failed") 
    } 

Однако это может быть не самая лучшая реализация, потому что процесс хранения данных кажется трудоемким.

Вот почему я планирую использовать UnsafePointer для передачи указателя от floatArray до inputForFunction, но я не уверен, как его реализовать. Просто для информации, один способ, которым я имею в виду, чтобы использовать withUnsafePointer метод непосредственно:

var floatArray: [Float] = try originalHDF5DataSet.read() 
var inputForFunction = UnsafeMutablePointer<Float>.allocate(capacity: Int(sizeOfArray)) 
withUnsafePointer(to: &floatArray[0]) { (ptr: UnsafePointer<Float>) in 
    inputForFunction = UnsafeMutablePointer(mutating: ptr) 
} 

или другой способ заключается в использовании withMemoryRebound (но следующее не работает):

var floatArray: [Float] = try originalHDF5DataSet.read() 
var inputForFunction = UnsafeMutablePointer<Float>.allocate(capacity: Int(sizeOfArray)) 
withUnsafePointer(to: &floatArray) { (ptrDataArray: UnsafePointer<[Float]>) in 
    inputForFunction = ptrDataArray.withMemoryRebound(to: inputForFunction.self, capacity: Int(sizeOfArray), { (ptr: UnsafePointer<[Float]>) -> UnsafeMutablePointer<Float> in 
    return ptr[0] 
    }) 
} 

Мой вопрос

  • Как передать адрес данных floatArray «S в inputForFunction?
  • Если мне нужно преобразовать из UnsafePointer < [Float]> в Unsafe [Mutable] Pointer, как это сделать?
  • При необходимости, как использовать withMemoryRebound для этой цели? Могу ли я присвоить адрес/значение inputForFunction внутри крышки?
  • Когда я проверил адреса floatArray и floatArray[0], они были разными (это кажется отличным от C/C++). Какой адрес следует передать inputForFunction?
+0

Как * точно * является функцией, объявленной для передачи данных? –

+0

Это для CNN на iOS. вход для kernelWeights и смещения. инициализации (устройство: MTLDevice, convolutionDescriptor fullyConnectedDescriptor: MPSCNNConvolutionDescriptor, kernelWeights: UnsafePointer , biasTerms: UnsafePointer , флаги:? MPSCNNConvolutionFlags) [Справочник по API из 'withUnsafeBufferPointer'] – kangaroo

ответ

2

Вы можете найти много статей, объясняющих, как вы можете получить Unsafe(Mutable)Pointer<Float> от [Float]. Некоторые из них отвечают на некоторые из ваших вопросов. Попробуйте найти их позже.

  • Как передать адрес данных floatArray, чтобы inputForFunction?

    Вы обычно используете методы Array withUnsafeBufferPointer или withUnsafeMutableBufferPointer. Вы можете получить Unsafe(Mutable)BufferPointer<Element> внутри параметра закрытия, который содержит Unsafe(Mutable)Pointer<Element> как его baseAddress.

    var floatArray: [Float] = try originalHDF5DataSet.read() 
    floatArray.withUnsafeBufferPointer {unsafeBufferPointer in 
        let inputForFunction = unsafeBufferPointer.baseAddress 
        //`unsafeBufferPointer` (including its `baseAddress`) is valid only in this closure. 
        //So, do not pass `inputForFunction` outside of the closure, use it inside. 
        //... 
    } 
    
  • Если мне нужно преобразовать из UnsafePointer < [Float]> в небезопасных [Мутабельном] Указатель, как это сделать?

    Когда вы найдете что-то вроде UnsafePointer<[Float]>, тогда вы идете не так. В Swift Array - это скрытая структура, которая может содержать (многоуровневую) косвенную ссылку на ее элементы. Обычно вам не нужно использовать UnsafePointer<Array<Float>>.

  • При необходимости, как использовать withMemoryRebound для этой цели? Могу ли я присвоить адрес/значение входной функции внутри закрытия?

    Если у вас есть массив AType и хотите, чтобы передать его в качестве Unsafe(Mutable)Pointer<AnotherType>, вы можете использовать withMemoryRebound. Но в вашем случае вам нужно только работать с Float, поэтому withMemoryRebound может не понадобиться для вашей цели.

  • Когда я проверил адреса floatArray и floatArray [0], они были разными (это кажется отличным от C/C++). Какой адрес следует передать на вход forFunction?

    Отсутствует. Как я писал выше, адрес floatArray просто указывает куда-то, где содержится скрытая структура, поэтому она абсолютно бесполезна для вашей цели. И адрес floatArray [0] не гарантированно является адресом первого элемента всего контента. Swift может создать временную область, которая содержит только один элемент и передаёт адрес временной области.


Кстати, действительно ли вы должны преобразовать ваш [Float] в Unsafe(Mutable)Pointer<Float>?

Если подпись ваших функций является чем-то вроде этого:

func takingUnsafePointer(_ pointer: UnsafePointer<Float>) 

Вы можете назвать это нравится:

takingUnsafePointer(floatArray) 
//In this case `floatArray` can be a `let` constant. 

Или же, если функция подписи:

func takingUnsafeMutablePointer(_ pointer: UnsafeMutablePointer<Float>) 

Назовите его как:

takingUnsafeMutablePointer(&floatArray) 
//In this case `floatArray` needs to be a `var`, not `let`. 

Помните, что в обоих случаях переданный указатель действителен только во время вызова функции. Вы не должны экспортировать указатель в другое место.

+0

Может быть, мне не нужно конвертировать. Если я передаю 'floatArray' в качестве аргумента, значит ли это передать адрес массива как константу let? – kangaroo

+1

@kazoo, я думаю, что могу сказать «да». Проверьте [эту часть] (https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-ID23) [Использование книги] (https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216). Даже литерал Array может быть передан аргументу const-указателя функции C. – OOPer

+0

Я получил его для этой части. Я все еще не уверен в различии, чтобы передать baseAddress и floatArray. Я напечатал фактическое значение адреса и обнаружил, что они разные. Кроме того, baseAddress и адрес floatArray [0] были одинаковыми.). Как вы уже упоминали, floatArray указывает куда-то со скрытой структурой. Если да, можно ли передать целые данные floatArray в функцию, передав 'floatArray'? Должен ли я использовать baseAddress вместо этого? Или оба полностью одинаковы? – kangaroo

1

Array тип есть withUnsafeBufferPointer способ.

Этот метод принимает замыкание с UnsafeBufferPointer, который похож на UnsafePointer<[Float]>, о котором вы просите.

Для размещения UnsafePointer в начало Array вы можете использовать baseAddress property of UnsafeBufferPointer.

Пример кода:

let bufferPointer: UnsafeBufferPointer<Float> = floatArray.withUnsafeBufferPointer { bufferPointer in 
    return bufferPointer 
} 

или

let baseAddress: UnsafePointer<Float> = floatArray.withUnsafeBufferPointer { bufferPointer in 
    return bufferPointer.baseAddress 
} 

EDIT: Или, если это функция только проездом &floatArray может работать.

+1

компании Apple (https://developer.apple.com/reference/ swift/contiguousarray/1538290-withunsafebufferpointer) четко заявляет, что ** Аргумент указателя действителен только для продолжительности выполнения закрытия. ** Лучше не экспортировать 'bufferPointer' или его' baseAddress' вне закрытия. К сожалению, ваш код может работать в некоторых ограниченных условиях, но условия не указаны. Вам следует избегать такого рискованного использования. – OOPer

+0

@OOPer, ну это «Небезопасно». И да, я думаю, что для выполнения задачи Op может быть достаточно выполнить '& floatArray' в func. – user28434

+0

_I думаю, что для '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'может быть достаточно, чтобы решить проблему Op._ Я согласен. Ваш ** EDIT ** может быть лучшим решением для OP. Итак, я добавил последнюю часть в свой ответ. – OOPer