从Swift 4调用C函数

时间:2019-07-26 01:35:07

标签: c swift matlab

我已经使用codegen工具从MATLAB生成了C代码。该功能可以描述如下:

function [result] = calculate_data(my_matrix)
    for idx = 1:length(my_matrix)
        result = result + sum(my_matrix(idx,1:3));
    end
end

在使用codegen工具时,我明确声明my_matrix是double(:inf,3)的一种。换句话说,行数是无限制的,但是它将有3列。生成代码后,这就是我要执行的生成的函数:

calculate_data(my_matrix : UnsafePointer<emxArray_real_T>!, result : UnsafeMutablePointer<emxArray_real_T>!)

emxArray_real_T在另一个c文件中的定义如下:

struct emxArray_real_T
{
  double *data;
  int *size;
  int allocatedSize;
  int numDimensions;
  boolean_T canFreeData;
};

当我看到上述类的初始化选项时,这一点特别有意义:

emxArray_real_T.init(data: UnsafeMutablePointer<Double>!, size: UnsafeMutablePointer<Int32>!, allocatedSize: Int32, numDimensions: Int32, canFreeData: boolean_T)

我试图遵循this document来绕过如何调用生成的C代码的方法,但是我认为我可能缺少一个基本步骤。这是我在做什么:

// create an 2d array with some fake data
var mySampleData = [[Double]]();
for i in 0 ..< 3 {
    mySampleData.append([1.1, 2.2, 3.3]);
}

// begin fulfilling requirements for emxArray_real_T
var data_pointer = UnsafeMutablePointer<Double>.allocate(capacity: 3);
data_pointer.initialize(from: mySampleData)

但是,上面的代码引发了一个错误,指出:

Generic parameter 'C' could not be inferred

我认为自己当时所做的事情完全错误,并且可能在错误的路径上。有一个类似的帖子与我的问题How to convert float[][] type array to "emxArray_real_T *x"有关,但是提供的解决方案似乎是针对C的,而不是针对Swift 4的。我如何才能使用Swift 4有效地调用C函数并满足要求的emxArray_real_T.init方法?可以使用伪造的数据来演示基本原理。

1 个答案:

答案 0 :(得分:4)

在一个简单的Xcode项目中,该项目具有针对结构emxArray_real_T和函数calculate_data的模拟C结构,我可以成功运行以下代码。要创建类型为emxArray_real_T的对象

var data: [Double] = (0 ..< 12).map(Double.init)
var size: [Int32] = [4, 3]

var array = emxArray_real_T(
    data: &data,
    size: &size,
    allocatedSize: 12,
    numDimensions: 2,
    canFreeData: false
)

该对象可以像calculate_data一样传递给函数calculate_data(&array, nil)。在实际的应用程序中,nil将是另一个数组对象。为了简单起见,此处仅将其用作占位符。

您可以通过使用正确的类型(第6行中的[Double]而非Double)解决第二个问题:

var mySampleData = [[Double]]();
for i in 0 ..< 3 {
    mySampleData.append([i*1, i*2, i*3].map(Double.init));
}

let pointer = UnsafeMutablePointer<[Double]>.allocate(capacity: 3)
pointer.initialize(from: mySampleData, count: 3)

print((pointer + 0).pointee)
print((pointer + 1).pointee)
print((pointer + 2).pointee)

pointer.deallocate()

输出将为

[0.0, 0.0, 0.0]
[1.0, 2.0, 3.0]
[2.0, 4.0, 6.0]

符合预期。

我必须承认我使用了Swift 5.0.1。不过,这应该不会产生重大差异。