我有一個如下所示的 C API:
typedef struct Datapoints {
double *ptr;
uintptr_t len;
} Datapoints;
double my_function(const struct Datapoints *baseline_data,
uint32_t baseline_data_len,
const struct Datapoints *new_data);
我發現很難從 Swift 中呼叫它。第一個引數是指向結構的指標陣列,Datapoints第三個引數是單個Datapoints結構。
這就是我想出的,但由于幾個原因它不起作用,主要原因是我試圖存盤一個不安全指標串列,以便以后將它們傳遞給my_function. 我通過重命名變數和型別對代碼進行了一些混淆,所以如果它不能編譯,請原諒我。代碼基本上是這樣的:
var baseline_datapoints = [Datapoints]()
var current_datapoints:Datapoints = Datapoints()
// This loop was intended to build up an array `baseline_Datapoints` containing pointers to struct `Datapoints`
for reading in baseline {
let datapoints:[Double] = reading.datapoints
// Won't work: The pointer passed as an argument to `body` is valid only during the
// execution of `withUnsafeMutableBufferPointer(_:)`. Do not store or return
// the pointer for later use.
// We _are_ attempting to store it for later use. ????
datapoints.withUnsafeMutableBufferPointer{ ptr in
baseline_datapoints.append(Datapoints(ptr: ptr.baseAddress, len: UInt(datapoints.count)) )
}
}
self.newData.withUnsafeMutableBufferPointer {ptr in
current_datapoints = Datapoints(ptr: ptr.baseAddress, len: UInt(self.newData.count))
}
let x = baseline_datapoints.withUnsafeBufferPointer{
(baselineptr: UnsafeBufferPointer<Datapoints>) -> Double in
return withUnsafePointer(to: current_datapoints) {
(current_ptr: UnsafePointer<Datapoints>) -> Double in
return my_function(baseline_ptr.baseAddress, UInt32(baseline_datapoints.count ), current_ptr)
}
}
我認為我應該做的是擴展withUnsafeXxxPointer閉包的范圍,以便資料保持足夠長的時間有效。但是,我不確定在嘗試建立baseline_data串列時該怎么做。
此外,為每個不安全的指標使用一個閉包似乎很不方便。如果我這樣做,它會導致代碼嵌套很深。還有其他方法可以做到這一點嗎?
歡迎任何建議。
編輯:
接受的答案作業得很好,除了第三個引數是按值傳遞的。然而,無論如何,這對于 C API 來說是一個更好的設計,所以我將我的 API 更改為:
double my_function(const struct Datapoints *baseline_data,
uint32_t baseline_data_len,
const struct Datapoints new_data);
兩者baseline_data都new_data在引數中,用于記錄。
uj5u.com熱心網友回復:
不幸的現實是,在 Swift 中存盤和重用ptr.baseAddress傳遞給datapoints.withUnsafeMutableBufferPointer. 這是記錄在案的:
…指標引數僅在方法執行期間有效。
這意味著您無法在回圈*中執行您嘗試執行的操作for,這同樣適用于您baseAddress從self.newData.withUnsafeMutableBufferPointer { }.
最干凈、最安全的解決方案將需要實際復制底層的 Doubles。這看起來更像:
var baseline_bufs = [UnsafeMutableBufferPointer<Double>]()
defer {
// don't forget to deallocate memory that was allocated!
for d in baseline_bufs {
d.deallocate()
}
}
// Copy data from baseline readings into UnsafeMutableBufferPointers
for reading in baseline {
d = UnsafeMutableBufferPointer<Double>.allocate(capacity: reading.datapoints.count)
d.initialize(from: reading.datapoints)
baseline_bufs.append(d)
}
let x = self.newData.withUnsafeMutableBufferPointer { newDataBuf in
let new_ptr = Datapoints(ptr: newDataBuf.baseAddress, len: UInt(newDataBuf.count))
// convert each `UnsafeMutableBufferPointer` to a `Datapoints`
let baseline_datapoints = baseline_bufs.map { Datapoints(ptr: $0.baseAddress, len: UInt($0.count)) }
return baseline_datapoints.withUnsafeBufferPointer {
return my_function($0.baseAddress, UInt32($0.count), new_ptr)
}
}
*也許有一些方法可以使用遞回來嵌套所有 withUnsafeX 呼叫,但是您會遇到堆疊大小限制,具體取決于陣列中的專案數。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/533054.html
標籤:C迅速菲
上一篇:底部作業表導致父視圖移動
