11

I'm writing a MsgPack parser in Swift as a way to learn the language. It doesn't feel very well suited to the task but I've been making progress. Now I've hit a block where I can't seem to convince it to convert 4 bytes into a float.

var bytes:Array<UInt8> = [0x9A, 0x99, 0x99, 0x41] //19.20000

var f:Float = 0

memccpy(&f, &bytes, 4, 4)

print(f)

In the playground I get:

fatal error: Can't unwrap Optional.None Playground execution failed: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).

Any ideas what to try next?

spenibus
  • 4,339
  • 11
  • 26
  • 35
Brian
  • 772
  • 1
  • 13
  • 31
  • Same question, swift 5 answer: https://stackoverflow.com/questions/41161034/how-to-convert-bytes-to-a-float-value-in-swift – itMaxence Jul 09 '19 at 15:37

2 Answers2

15

Drop the & on &bytes. bytes is an array.

    var bytes:Array<UInt8> = [0x9A, 0x99, 0x99, 0x41] //19.20000

    var f:Float = 0.0

    memccpy(&f, bytes, 4, 4) // as per OP. memcpy(&f, bytes, 4) preferred

    println ("f=\(f)")// f=19.2000007629395

Update Swift 3

memccpy does not seem to work in Swift 3. As commentators have said, use memcpy :

import Foundation
var bytes:Array<UInt8> = [0x9A, 0x99, 0x99, 0x41] //19.20000

var f:Float = 0.0

/* Not in Swift 3
 memccpy(&f, bytes, 4, 4) // as per OP.

 print("f=\(f)")// f=19.2
 */

memcpy(&f, bytes, 4) /

print("f=\(f)")// f=19.2
Grimxn
  • 22,115
  • 10
  • 72
  • 85
  • 5
    Better: `memcpy(&f, bytes, 4)`. - `memccpy(&f, bytes, 4, 4)` stops copying if the byte `0x04` occurs in the source buffer. – Martin R Jun 23 '14 at 08:31
  • Should `var` also be `let` to satisfy the constant requirement of the second parameter of memccpy()? This would've then displayed a compiler warning and forced &bytes to be written as bytes, even if it isn't strictly required. – sketchyTech Jun 23 '14 at 08:40
  • Thanks for the help. I still get the same error in the playground, in a project I works fine. – Brian Jun 23 '14 at 15:06
  • You can also do memcpy(&f, bytes, UInt(sizeof(Float))), though this is a bit ugly and you hardcode the array size anyways. Maybe an assert(sizeof(Float) == 4). – hnh Jun 24 '14 at 08:42
  • @MartinR & Grimxn - Should you use ContiguousArray instead of Array? – MirekE Oct 05 '15 at 04:04
  • @MirekE - I answered the question but frankly would never use `memccpy` in my own code. When I have to do that kind of thing, I would prefer to use `NSData`'s `getBytes` / `bytes`... – Grimxn Oct 05 '15 at 08:08
3
public func parseInt32(bytes:[UInt8], offset:Int)->Int32{

    var pointer = UnsafePointer<UInt8>(bytes)
    pointer = pointer.advancedBy(offset)

    let iPointer =  UnsafePointer<Int32>(pointer)
    return iPointer.memory

}

public func parseFloat32(bytes:[UInt8], offset:Int)->Float32{
    var pointer = UnsafePointer<UInt8>(bytes)
    pointer = pointer.advancedBy(offset)

    let fPointer =  UnsafePointer<Float32>(pointer)
    return fPointer.memory

}
Jagie
  • 2,190
  • 3
  • 27
  • 25