26

How can one pass or copy the data in a C array, such as

float foo[1024];

, between C and Swift functions that use fixed size arrays, such as declared by

let foo = Float[](count: 1024, repeatedValue: 0.0)

?

hotpaw2
  • 70,107
  • 14
  • 90
  • 153

3 Answers3

21

I don't think this is easily possible. In the same way as you can't use C style arrays for parameters working with a NSArray.

All C arrays in Swift are represented by an UnsafePointer, e.g. UnsafePointer<Float>. Swift doesn't really know that the data are an array. If you want to convert them into a Swift array, you will have create a new object and copy the items there one by one.

let array: Array<Float> = [10.0, 50.0, 40.0]

// I am not sure if alloc(array.count) or alloc(array.count * sizeof(Float))
var cArray: UnsafePointer<Float> = UnsafePointer<Float>.alloc(array.count)
cArray.initializeFrom(array)

cArray.dealloc(array.count)

Edit

Just found a better solution, this could actually avoid copying.

let array: Array<Float> = [10.0, 50.0, 40.0]

// .withUnsafePointerToElements in Swift 2.x
array.withUnsafeBufferPointer() { (cArray: UnsafePointer<Float>) -> () in
    // do something with the C array
}
Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • Surely the array with unsafe pointer must copy the contents, as it doesn't know how long it will stay allocated? – jhabbott Apr 29 '15 at 04:16
  • @jhabbott That's why it's "unsafe" :). Depending on the internal representation of Array<> it may have to perform a copy to a contiguous memory area if it doesn't already exist in one, but this is probably reasonably unlikely/infrequent in practice. – Ephemera Sep 10 '15 at 08:08
  • 3
    Looks like ```withUnsafePointerToElements``` was removed: https://developer.apple.com/library/mac/releasenotes/General/APIDiffsMacOSX10_10_3/modules/Swift.html – marchinram Feb 01 '16 at 21:32
  • U saved my life – tatiana_c Apr 02 '17 at 18:11
12

As of Beta 5, one can just use pass &array The following example passes 2 float arrays to a vDSP C function:

let logLen = 10
let len = Int(pow(2.0, Double(logLen)))
let setup : COpaquePointer = vDSP_create_fftsetup(vDSP_Length(logLen), FFTRadix(kFFTRadix2))

var myRealArray = [Float](count: len, repeatedValue: 0.0)
var myImagArray = [Float](count: len, repeatedValue: 0.0)
var cplxData = DSPSplitComplex(realp: &myRealArray, imagp: &myImagArray)

vDSP_fft_zip(setup, &cplxData, 1, vDSP_Length(logLen),FFTDirection(kFFTDirection_Forward))
hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • 11
    How about an example that doesn't show real world code? It's not very clear which parts are what you're trying to demonstrate and which are just part of the C API you're using. – Abhi Beckert Aug 15 '14 at 04:36
  • @AbhiBeckert DSPSplitComplex is a part of the Apple Accelerate framework which is a C API and is a good example. It is a simple struct for holding a vector of complex numbers. – Cameron Lowell Palmer Feb 09 '16 at 13:31
  • 1
    As of Swift 3, Array init is now: `var myRealArray = [Float](repeating: 0.0, count: len)` – Nicolas Buquet Nov 04 '16 at 08:28
11

The withUnsafePointerToElements() method was removed, now you can use the withUnsafeBufferPointer() instead, and use the baseAddress method in the block to achieve the point

let array: Array<Float> = [10.0, 50.0, 40.0]
array.withUnsafeBufferPointer { (cArray: UnsafePointer<Float>) -> () in
    cArray.baseAddress
}
Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
yglixm
  • 121
  • 1
  • 2