Swift桥接2D数组到类型UnsafePointer<;非女性化指针<;双倍>>;?
嗨,我正在尝试使用Swift 4包装一个C api Swift已导入具有以下签名的函数Swift桥接2D数组到类型UnsafePointer<;非女性化指针<;双倍>>;?,swift,pointers,pointer-to-pointer,c-api,Swift,Pointers,Pointer To Pointer,C Api,嗨,我正在尝试使用Swift 4包装一个C api Swift已导入具有以下签名的函数 public-typealias-indicator=@convention(c)(Int32,UnsafePointer?,UnsafePointer?,UnsafePointer?),Int32 根据C库文件,签名如下: typedef int (*indicator_function)(int size, double const *const *inputs, double const *op
public-typealias-indicator=@convention(c)(Int32,UnsafePointer?,UnsafePointer?,UnsafePointer?),Int32
根据C库文件,签名如下:
typedef int (*indicator_function)(int size,
double const *const *inputs,
double const *options,
double *const *outputs);
typedef struct indicator_info {
char *name;
char *full_name;
indicator_start_function start;
indicator_function indicator;
int type, inputs, options, outputs;
char *input_names[MAXINDPARAMS];
char *option_names[MAXINDPARAMS];
char *output_names[MAXINDPARAMS];
} indicator_info;
let inputs = [1.0, 2.0]
let options = [1.0, 1.0]
var outputs = [0.0, 0.0]
let result:Int32 = withUnsafePointer(to: inputs) { inputsPtr in
withUnsafePointer(to: &outputs) { outputsPtr in
indicator_abs(2,inputsPtr,options,outputsPtr)
}
}
int指示器(int大小,
双常量*常量*输入,
双常量*选项,
双*常数*输出)代码>
值得注意的是,函数返回的int
是c风格的函数错误类型,实际返回在输出
指针中
那么假设我创建了以下Swift类型
让输入:[[Double]]=[]
让选项:[加倍]=[]
变量输出:[[Double]]=[]
有了一些合适的值,我应该可以做如下事情:(注意info.pointee.indicator
是导入的函数)
指示器
功能可通过上述结构访问
指示符函数的给定实例如下所示
int add(int size,
TI_REAL const *const *inputs,
TI_REAL const *options,
TI_REAL *const *outputs);
假设您有一个C函数,正如您在注释中所述,Swift键入的函数如下:
public func indicator_abs(_ size: Int32,
_ inputs: UnsafePointer<UnsafePointer<Double>?>!,
_ options: UnsafePointer<Double>!,
_ outputs: UnsafePointer<UnsafeMutablePointer<Double>?>!) -> Int32
这里的问题在于C API需要这些参数double*const*输出
和double-const*const*输入
,或者用Swift术语[[double]]
类型
该C
功能签名由Swift分别导入以下类型
UnsafePointer<UnsafeMutablePointer<Double>?>
UnsafePointer<UnsafePointer<Double>?>
由于转义桥接指针是未定义的行为,因此有必要在闭包内进行桥接和调用,正如Ole Bergmann在其文章中所建议的那样
为此,我们创建了一个类似的函数:
func indicatorWithArrays<R>(inputs ins:[[Double]],
options opts: [Double],
outputs out: [[Double]],
ti body: ([UnsafePointer<Double>?],
UnsafePointer<Double>?,
[UnsafeMutablePointer<Double>?]) -> R) -> R
return indicatorWithArrays(inputs: input, options: opts, outputs: resArray) { (input, opts, outputs) in
let sz = inputs?.first?.count ?? 0
switch TIReturnType(rawValue: tulipInfo.info.pointee.indicator(Int32(sz), input, opts, outputs)) {
case .ti_okay?:
for (index, item) in outputs.enumerated() {
let buff = UnsafeBufferPointer(start: item, count: resArray[index].count)
resArray[index] = Array(buff)
}
return resArray
case nil:
return nil
}
}
将[UnsafePointer]
参数传递到主体
闭包会隐式连接到导入的C API所需的UnsafePointer
和UnsafePointer
调用indicatorWithArrays
函数如下,允许我们在导入的C函数中使用桥接指针:
func indicatorWithArrays<R>(inputs ins:[[Double]],
options opts: [Double],
outputs out: [[Double]],
ti body: ([UnsafePointer<Double>?],
UnsafePointer<Double>?,
[UnsafeMutablePointer<Double>?]) -> R) -> R
return indicatorWithArrays(inputs: input, options: opts, outputs: resArray) { (input, opts, outputs) in
let sz = inputs?.first?.count ?? 0
switch TIReturnType(rawValue: tulipInfo.info.pointee.indicator(Int32(sz), input, opts, outputs)) {
case .ti_okay?:
for (index, item) in outputs.enumerated() {
let buff = UnsafeBufferPointer(start: item, count: resArray[index].count)
resArray[index] = Array(buff)
}
return resArray
case nil:
return nil
}
}
其中调用为:tulipInfo.info.pointee.indicator(Int32(sz)、输入、选择、输出)
神奇之处在于在函数之间传递闭包,从而确保我们不会逃过桥接指针。Ole Bergmann的解决方案适用于字符串
类型,但希望这能帮助其他被类型
[[t]]“Swift已导入具有以下签名的函数”不。根据这一点,指示器
不是您调用的函数。它是您传递的函数的类型(签名)。显示实际必须传递它的C API。它是一组函数的类型别名,所有这些函数都具有以下签名public func indicator\u abs(uusize:Int32,uinput:UnsafePointer!,options:UnsafePointer!,uuOutputs:UnsafePointer!)->Int32
。我已经编辑了这个问题。谢谢,但是有两件事,参数输入
和输出
属于[[Double]]
类型,而且在C样式中结果
是输出
中所需的函数的错误类型。因此,我认为这是行不通的,因为我认为我们无法逃避outputsPtr
return ins.withUnsafeBufferPointer { (inputsBuffer) in
var inPuts: [UnsafePointer<Double>?] = inputsBuffer.map { UnsafePointer($0) }
return out.withUnsafeBufferPointer { (outputsBuffer) in
var outPtrPtr: [UnsafeMutablePointer<Double>?]
= outputBuffer.map { UnsafeMutablePointer(mutating: $0) }
return body(inPuts, opts, outPtrPtr)
}
}
return indicatorWithArrays(inputs: input, options: opts, outputs: resArray) { (input, opts, outputs) in
let sz = inputs?.first?.count ?? 0
switch TIReturnType(rawValue: tulipInfo.info.pointee.indicator(Int32(sz), input, opts, outputs)) {
case .ti_okay?:
for (index, item) in outputs.enumerated() {
let buff = UnsafeBufferPointer(start: item, count: resArray[index].count)
resArray[index] = Array(buff)
}
return resArray
case nil:
return nil
}
}