Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift桥接2D数组到类型UnsafePointer<;非女性化指针<;双倍>>;?_Swift_Pointers_Pointer To Pointer_C Api - Fatal编程技术网

Swift桥接2D数组到类型UnsafePointer<;非女性化指针<;双倍>>;?

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

嗨,我正在尝试使用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 *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
            }
        }