我有一个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);
第一个参数是一个指向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
均在参数中,以备记录。
1条答案
按热度按时间6bc51xsx1#
不幸的是,在Swift中,在传递给
datapoints.withUnsafeMutableBufferPointer
的闭包之外存储和重用ptr.baseAddress
的值是不安全的。...指针参数只在方法执行期间有效。
这意味着,在
for
循环 * 中无法执行您尝试执行的操作,而让baseAddress
从self.newData.withUnsafeMutableBufferPointer { }
中逃逸的方法也是如此。最干净、最安全的解决方案是需要实际 * 复制 * 基础Double。看起来更像这样: