Printing a variable memory address in swift - swift

Is there anyway to simulate the [NSString stringWithFormat:#"%p", myVar], from Objective-C, in the new Swift language?
For example:
let str = "A String"
println(" str value \(str) has address: ?")

Note: This is for reference types.
Swift 4/5:
print(Unmanaged.passUnretained(someVar).toOpaque())
Prints the memory address of someVar.
(thanks to #Ying)
Swift 3.1:
print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Prints the memory address of someVar.

Swift 2
This is now part of the standard library: unsafeAddressOf.
/// Return an UnsafePointer to the storage used for `object`. There's
/// not much you can do with this other than use it to identify the
/// object
Swift 3
For Swift 3, use withUnsafePointer:
var str = "A String"
withUnsafePointer(to: &str) {
print(" str value \(str) has address: \($0)")
}

Note that this answer was quite old. Many of the methods it describes no longer work. Specifically .core cannot be accessed anymore.
However #drew's answer is correct and simple:
This is now part of the standard library: unsafeAddressOf.
So the answer to your questions is:
println(" str value \(str) has address: \(unsafeAddressOf(str))")
Here is the original answer that was marked correct (for posterity/politeness):
Swift "hides" pointers, but they still exists under the hood. (because the runtime needs it, and for compatibility reasons with Objc and C)
There are few things to know however, but first how to print the memory address of a Swift String?
var aString : String = "THIS IS A STRING"
NSLog("%p", aString.core._baseAddress) // _baseAddress is a COpaquePointer
// example printed address 0x100006db0
This prints the memory address of the string, if you open XCode -> Debug Workflow -> View Memory and go to the printed address, you will see the raw data of the string.
Since this is a string literal, this is a memory address inside the storage of the binary (not stack or heap).
However, if you do
var aString : String = "THIS IS A STRING" + "This is another String"
NSLog("%p", aString.core._baseAddress)
// example printed address 0x103f30020
This will be on the stack, because the string is created at runtime
NOTE: .core._baseAddress is not documented, I found it looking in the variable inspector, and it may be hidden in the future
_baseAddress is not available on all types, here another example with a CInt
var testNumber : CInt = 289
takesInt(&testNumber)
Where takesInt is a C helper function like this
void takesInt(int *intptr)
{
printf("%p", intptr);
}
On the Swift side, this function is takesInt(intptr: CMutablePointer<CInt>), so it takes a CMutablePointer to a CInt, and you can obtain it with &varname
The function prints 0x7fff5fbfed98, an at this memory address you will find 289 (in hexadecimal notation). You can change its content with *intptr = 123456
Now, some other things to know.
String, in swift, is a primitive type, not an object.
CInt is a Swift type mapped to the C int Type.
If you want the memory address of an object, you have to do something different.
Swift has some Pointer Types that can be used when interacting with C, and you can read about them here: Swift Pointer Types
Moreover, you can understand more about them exploring their declaration (cmd+click on the type), to understand how to convert a type of pointer into another
var aString : NSString = "This is a string" // create an NSString
var anUnmanaged = Unmanaged<NSString>.passUnretained(aString) // take an unmanaged pointer
var opaque : COpaquePointer = anUnmanaged.toOpaque() // convert it to a COpaquePointer
var mut : CMutablePointer = &opaque // this is a CMutablePointer<COpaquePointer>
printptr(mut) // pass the pointer to an helper function written in C
printptr is a C helper function I created, with this implementation
void printptr(void ** ptr)
{
printf("%p", *ptr);
}
Again, an example of the address printed: 0x6000000530b0 , and if you go through memory inspector you will find your NSString
One thing you can do with pointers in Swift (this can even be done with inout parameters)
func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>)
{
stringa.memory = "String Updated";
}
var testString : NSString = "test string"
println(testString)
playWithPointer(&testString)
println(testString)
Or, interacting with Objc / c
// objc side
+ (void)writeString:(void **)var
{
NSMutableString *aString = [[NSMutableString alloc] initWithFormat:#"pippo %#", #"pluto"];
*var = (void *)CFBridgingRetain(aString); // Retain!
}
// swift side
var opaque = COpaquePointer.null() // create a new opaque pointer pointing to null
TestClass.writeString(&opaque)
var string = Unmanaged<NSString>.fromOpaque(opaque).takeRetainedValue()
println(string)
// this prints pippo pluto

TL;DR
struct MemoryAddress<T>: CustomStringConvertible {
let intValue: Int
var description: String {
let length = 2 + 2 * MemoryLayout<UnsafeRawPointer>.size
return String(format: "%0\(length)p", intValue)
}
// for structures
init(of structPointer: UnsafePointer<T>) {
intValue = Int(bitPattern: structPointer)
}
}
extension MemoryAddress where T: AnyObject {
// for classes
init(of classInstance: T) {
intValue = unsafeBitCast(classInstance, to: Int.self)
// or Int(bitPattern: Unmanaged<T>.passUnretained(classInstance).toOpaque())
}
}
/* Testing */
class MyClass { let foo = 42 }
var classInstance = MyClass()
let classInstanceAddress = MemoryAddress(of: classInstance) // and not &classInstance
print(String(format: "%018p", classInstanceAddress.intValue))
print(classInstanceAddress)
struct MyStruct { let foo = 1 } // using empty struct gives weird results (see comments)
var structInstance = MyStruct()
let structInstanceAddress = MemoryAddress(of: &structInstance)
print(String(format: "%018p", structInstanceAddress.intValue))
print(structInstanceAddress)
/* output
0x0000000101009b40
0x0000000101009b40
0x00000001005e3000
0x00000001005e3000
*/
(Gist)
In Swift we deal either with value types (structures) or reference types (classes). When doing:
let n = 42 // Int is a structure, i.e. value type
Some memory is allocated at address X, and at this address we will find the value 42. Doing &n creates a pointer pointing to address X, therefore &n tells us where n is located.
(lldb) frame variable -L n
0x00000001005e2e08: (Int) n = 42
(lldb) memory read -c 8 0x00000001005e2e08
0x1005e2e08: 2a 00 00 00 00 00 00 00 // 0x2a is 42
When doing:
class C { var foo = 42, bar = 84 }
var c = C()
Memory is allocated in two places:
at address Y where the class instance data is located and
at address X where the class instance reference is located.
As said, classes are reference types: so the value of c is located at address X, at which we'll find the value of Y. And at address Y + 16 we'll find foo and at address Y + 24 we'll find bar (at + 0 and + 8 we'll find type data and reference counts, I can't tell you much more about this...).
(lldb) frame variable c // gives us address Y
(testmem.C) c = 0x0000000101a08f90 (foo = 42, bar = 84)
(lldb) memory read 0x0000000101a08f90 // reading memory at address Y
0x101a08f90: e0 65 5b 00 01 00 00 00 02 00 00 00 00 00 00 00
0x101a08fa0: 2a 00 00 00 00 00 00 00 54 00 00 00 00 00 00 00
0x2a is 42 (foo) and 0x54 is 84 (bar).
In both cases, using &n or &c will give us address X. For value types, that's what we want, but isn't for reference types.
When doing:
let referencePointer = UnsafeMutablePointer<C>(&c)
We create a pointer on the reference, i.e. a pointer that points to address X. Same thing when using withUnsafePointer(&c) {}.
(lldb) frame variable referencePointer
(UnsafeMutablePointer<testmem.C>) referencePointer = 0x00000001005e2e00 // address X
(lldb) memory read -c 8 0x00000001005e2e00 // read memory at address X
0x1005e2e00: 20 ec 92 01 01 00 00 00 // contains address Y, consistent with result below:
(lldb) frame variable c
(testmem.C) c = 0x000000010192ec20 (foo = 42, bar = 84)
Now that we have a better understanding of what goes on under the hood, and that we now that at address X we'll find address Y (which is the one we want) we can do the following to get it:
let addressY = unsafeBitCast(c, to: Int.self)
Verifying:
(lldb) frame variable addressY -f hex
(Int) addressY = 0x0000000101b2fd20
(lldb) frame variable c
(testmem.C) c = 0x0000000101b2fd20 (foo = 42, bar = 84)
There are other ways to do this:
let addressY1 = Int(bitPattern: Unmanaged.passUnretained(c).toOpaque())
let addressY2 = withUnsafeMutableBytes(of: &c) { $0.load(as: Int.self) }
toOpaque() actually calls unsafeBitCast(c, to: UnsafeMutableRawPointer.self).
I hope this helped... it did for me 😆.

Swift 5
extension String {
static func pointer(_ object: AnyObject?) -> String {
guard let object = object else { return "nil" }
let opaque: UnsafeMutableRawPointer = Unmanaged.passUnretained(object).toOpaque()
return String(describing: opaque)
}
}
Usage:
print("FileManager.default: \(String.pointer(FileManager.default))")
// FileManager.default: 0x00007fff5c287698
print("nil: \(String.pointer(nil))")
// nil: nil

To get the (heap) address of an object
func address<T: AnyObject>(o: T) -> Int {
return unsafeBitCast(o, Int.self)
}
class Test {}
var o = Test()
println(NSString(format: "%p", address(o))) // -> 0x7fd5c8700970
(Edit: Swift 1.2 now includes a similar function called unsafeAddressOf.)
In Objective-C this would be [NSString stringWithFormat:#"%p", o].
o is a reference to the instance. So if o is assigned to another variable o2, the returned address for o2 will be the same.
This doesn't apply to structs (including String) and primitive types (like Int), because those live directly on the stack. But we can retrieve the location on the stack.
To get the (stack) address of a struct, build-in type or object reference
func address(o: UnsafePointer<Void>) -> Int {
return unsafeBitCast(o, Int.self)
}
println(NSString(format: "%p", address(&o))) // -> 0x10de02ce0
var s = "A String"
println(NSString(format: "%p", address(&s))) // -> 0x10de02ce8
var i = 55
println(NSString(format: "%p", address(&i))) // -> 0x10de02d00
In Objective-C this would be [NSString stringWithFormat:#"%p", &o] or [NSString stringWithFormat:#"%p", &i].
s is struct. So if s is assigned to another variable s2, the value will be copied and the returned address for s2 will be different.
How it fits together (pointer recap)
Like in Objective-C, there are two different addresses associated with o. The first is the location of the object, the second is the location of the reference (or pointer) to the object.
Yes, this means that the content of address 0x7fff5fbfe658 is the number 0x6100000011d0 as the debugger can tell us:
(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0
So, except for strings being structs, internally this all pretty much works the same as in (Objective-)C.
(Current as of Xcode 6.3)

Reference Types:
It makes sense to get the memory address of a reference type as it represents identity.
=== identity operator is used to check 2 objects point to the same reference.
Use ObjectIdentifier to get the memory address
Code:
class C {}
let c1 = C()
let c2 = c1
//Option 1:
print("c1 address: \(Unmanaged.passUnretained(c1).toOpaque())")
//Option 2:
let o1 = ObjectIdentifier(c1)
let o2 = ObjectIdentifier(c2)
print("o1 -> c1 = \(o1)")
print("o2 -> c2 = \(o2)")
if o1 == o2 {
print("c1 = c2")
} else {
print("c1 != c2")
}
//Output:
//c1 address: 0x000060c000005b10
//o1 -> c1 = ObjectIdentifier(0x000060c000005b10)
//o2 -> c2 = ObjectIdentifier(0x000060c000005b10)
//c1 = c2
Value Types:
The need to get the memory address of a value type is not of much significance (as it is a value) and the emphasis would be more on the equality of the value.

Just use this:
print(String(format: "%p", object))

If you just want to see this in the debugger and not do anything else with it, there's no need to actually get the Int pointer. To get the string representation of an object's address in memory, just use something like this:
public extension NSObject { // Extension syntax is cleaner for my use. If your needs stem outside NSObject, you may change the extension's target or place the logic in a global function
public var pointerString: String {
return String(format: "%p", self)
}
}
Example usage:
print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...
Additionally, remember that you can simply print an object without overriding its description, and it will show its pointer address alongside more descriptive (if oft cryptic) text.
print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...

In Swift4 about Array:
let array1 = [1,2,3]
let array2 = array1
array1.withUnsafeBufferPointer { (point) in
print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
}
array2.withUnsafeBufferPointer { (point) in
print(point) // UnsafeBufferPointer(start: 0x00006000004681e0, count: 3)
}

The answer #Drew provide can only be used for class type.
The answer #nschum provide can only be for struct type.
However if you use the second method to get address of a array with value type element. Swift will copy the whole array because in Swift array is copy-on-write and Swift can't make sure it behave this way once it pass control over to C/C++ (Which is trigger by using & to get address). And if you use first method instead , it will automatically convert Array to NSArray which is surely something we don't want.
So the most simple and unified way I found is using lldb instruction frame variable -L yourVariableName.
Or you can combine their answers:
func address(o: UnsafePointer<Void>) {
let addr = unsafeBitCast(o, Int.self)
print(NSString(format: "%p", addr))
}
func address<T: AnyObject>(o: T) -> String{
let addr = unsafeBitCast(o, Int.self)
return NSString(format: "%p", addr) as String
}

The other answers are fine, though I was looking for a way to get the pointer address as an integer:
let ptr = unsafeAddressOf(obj)
let nullPtr = UnsafePointer<Void>(bitPattern: 0)
/// This gets the address of pointer
let address = nullPtr.distanceTo(ptr) // This is Int
Just a little follow-up.

My solution on Swift 3
extension MyClass: CustomStringConvertible {
var description: String {
return "<\(type(of: self)): 0x\(String(unsafeBitCast(self, to: Int.self), radix: 16, uppercase: false))>"
}
}
this code create description like default description
<MyClass: 0x610000223340>

This is for Swift 3.
Like #CharlieMonroe I wanted to get the address as an integer. Specifically, I wanted the address of a Thread object for use as a thread ID in a diagnostic logging module, for situations where no thread name was available.
Based on Charlie Monroe's code, here's what I've come up with so far. But beware, I'm very new to Swift, this may not be correct ...
// Convert the memory address of the current Thread object into an Int for use as a thread ID
let objPtr = Unmanaged.passUnretained(Thread.current).toOpaque()
let onePtr = UnsafeMutableRawPointer(bitPattern: 1)! // 1 used instead of 0 to avoid crash
let rawAddress : Int64 = onePtr.distance(to: objPtr) + 1 // This may include some high-order bits
let address = rawAddress % (256 * 1024 * 1024 * 1024) // Remove high-order bits
The last statement is there because without it I was getting addresses like 0x60000007DB3F. The modulo operation in the last statement converts that into 0x7DB3F.

This is certainly not the fastest or safest way to go about it. But it works for me. This will allow for any nsobject subclass to adopt this property.
public extension NSObject {
public var memoryAddress : String? {
let str = "\(self.self)".components(separatedBy: ": ")
guard str.count > 1 else { return nil }
return str[1].replacingOccurrences(of: ">", with: "")
}
}
//usage
let foo : String! = "hello"
Swift.print(foo.memoryAddress) // prints 0x100f12980

Related

pointer arrays to String

I need to have a pointer array like in C, in Swift.
The following code works:
let ptr = UnsafeMutableBufferPointer<Int32>.allocate(capacity: 5)
ptr[0] = 1
ptr[1] = 5
print(ptr[0], ptr[1]) // outputs 1 5
The following code, however, does not work:
let ptr = UnsafeMutableBufferPointer<String>.allocate(capacity: 5)
print(ptr[0]) // Outputs an empty string (as expected)
print(ptr[1]) // Just exits with exit code 11
When I do print(ptr[1]) in the swift REPL, I get the following output:
Execution interrupted. Enter code to recover and continue.
Enter LLDB commands to investigate (type :help for assistance.)
How can I create a C-like array with Strings (or any other reference type, as this also doesn't seem to work with classes).
What should I adjust?
You need to initialize the memory with valid String data.
let values = ["First", "Last"]
let umbp = UnsafeMutableBufferPointer<String>.allocate(capacity: values.count)
_ = umbp.initialize(from: values)
print(umbp.map { $0 })
umbp[0] = "Joe"
umbp[1] = "Smith"
print(umbp.map { $0 })
Prints:
["First", "Last"]
["Joe", "Smith"]

How to prove "copy-on-write" on String type in Swift

As the title said, I tried to prove myself that COW(copy on write) is supported for String in Swift. But I cannot find a proof. I proved the COW on Array and Dictionary after trying the following codes:
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
var xArray = [20, 30, 40, 50, 60]
var yArray = xArray
// These two addresses were the same
address(of: xArray)
address(of: yArray)
yArray[0] = 200
// The address of yArray got changed
address(of: yArray)
But for String type, it was not working.
var xString = "Hello World"
var yString = xString
// These two addresses were different
address(of: xString)
address(of: yString)
And I dumped the test function from the official Swift code repo.
func _rawIdentifier(s: String) -> (UInt, UInt) {
let tripe = unsafeBitCast(s, to: (UInt, UInt, UInt).self)
let minusCount = (tripe.0, tripe.2)
return minusCount
}
But this function seems to only cast the actual value pointed to not the address. So two different String variables with the same value would have the same rawIdentifier. Still cannot prove COW to me.
var xString = "Hello World"
var yString = "Hello" + " World"
// These two rawIdentifiers were the same
_rawIdentifier(s: xString)
_rawIdentifier(s: yString)
So how does COW work on String type in Swift?
The compiler creates only a single storage for both
"Hello World" and "Hello" + " World".
You can verify that for example by examining the assembly code
obtained from
swiftc -emit-assembly cow.swift
which defines only a single string literal
.section __TEXT,__cstring,cstring_literals
L___unnamed_1:
.asciz "Hello World"
As soon as the string is mutated, the address of the string storage
buffer (the first member of that "magic" tuple, actually _baseAddress
of struct _StringCore, defined in StringCore.swift) changes:
var xString = "Hello World"
var yString = "Hello" + " World"
print(_rawIdentifier(s: xString)) // (4300325536, 0)
print(_rawIdentifier(s: yString)) // (4300325536, 0)
yString.append("!")
print(_rawIdentifier(s: yString)) // (4322384560, 4322384528)
And why does your
func address(of object: UnsafeRawPointer) -> String
function show the same values for xArray and yArray, but
not for xString and yString?
Passing an array to a function taking a unsafe pointer passes the
address of the first array element, that is the same for both
arrays if they share the storage.
Passing a string to a function taking an unsafe pointer passes a
pointer to a temporary UTF-8 representation of the string.
That address can be different in each call, even for the same string.
This behavior is documented in the "Using Swift with Cocoa and
Objective-C" reference for UnsafePointer<T> arguments, but apparently
works the same for UnsafeRawPointer arguments.

String convert to Int and replace comma to Plus sign

Using Swift, I'm trying to take a list of numbers input in a text view in an app and create a sum of this list by extracting each number for a grade calculator. Also the amount of values put in by the user changes each time. An example is shown below:
String of: 98,99,97,96...
Trying to get: 98+99+97+96...
Please Help!
Thanks
Use components(separatedBy:) to break up the comma-separated string.
Use trimmingCharacters(in:) to remove spaces before and after each element
Use Int() to convert each element into an integer.
Use compactMap (previously called flatMap) to remove any items that couldn't be converted to Int.
Use reduce to sum up the array of Int.
let input = " 98 ,99 , 97, 96 "
let values = input.components(separatedBy: ",").compactMap { Int($0.trimmingCharacters(in: .whitespaces)) }
let sum = values.reduce(0, +)
print(sum) // 390
For Swift 3 and Swift 4.
Simple way: Hard coded. Only useful if you know the exact amount of integers coming up, wanting to get calculated and printed/used further on.
let string98: String = "98"
let string99: String = "99"
let string100: String = "100"
let string101: String = "101"
let int98: Int = Int(string98)!
let int99: Int = Int(string99)!
let int100: Int = Int(string100)!
let int101: Int = Int(string101)!
// optional chaining (if or guard) instead of "!" recommended. therefore option b is better
let finalInt: Int = int98 + int99 + int100 + int101
print(finalInt) // prints Optional(398) (optional)
Fancy way as a function: Generic way. Here you can put as many strings in as you need in the end. You could, for example, gather all the strings first and then use the array to have them calculated.
func getCalculatedIntegerFrom(strings: [String]) -> Int {
var result = Int()
for element in strings {
guard let int = Int(element) else {
break // or return nil
// break instead of return, returns Integer of all
// the values it was able to turn into Integer
// so even if there is a String f.e. "123S", it would
// still return an Integer instead of nil
// if you want to use return, you have to set "-> Int?" as optional
}
result = result + int
}
return result
}
let arrayOfStrings = ["98", "99", "100", "101"]
let result = getCalculatedIntegerFrom(strings: arrayOfStrings)
print(result) // prints 398 (non-optional)
let myString = "556"
let myInt = Int(myString)

Why does Swift return an unexpected pointer when converting an optional String into an UnsafePointer?

I noticed some unusual behaviour when working with a C library which took strings in as const char * (which is converted to Swift as UnsafePointer<Int8>!); passing a String worked as expected, but a String? seemed to corrupt the input. Consider the test I wrote:
func test(_ input: UnsafePointer<UInt8>?) {
if let string = input {
print(string[0], string[1], string[2], string[3], string[4], string[5])
} else {
print("nil")
}
}
let input: String = "Hello"
test(input)
This works as expected, printing a null-terminated list of UTF-8 bytes for the input string: 72 101 108 108 111 0
However, if I change the input to an optional string, so that it becomes:
let input: String? = "Hello"
I get a completely different set of values in the result (176 39 78 23 1 0), even though I would expect it to be the same. Passing in nil works as expected.
The C library's function allows NULL in place of a string, and I sometimes want to pass that in in Swift as well, so it makes sense for the input string to be an optional.
Is this a bug in Swift, or was Swift not designed to handle this case? Either way, what's the best way to handle this case?
Edit
It appears to have something to do with multiple arguments. The C function:
void multiString(const char *arg0, const char *arg1, const char *arg2, const char *arg3) {
printf("%p: %c %c %c\n", arg0, arg0[0], arg0[1], arg0[2]);
printf("%p: %c %c %c\n", arg1, arg1[0], arg1[1], arg1[2]);
printf("%p: %c %c %c\n", arg2, arg2[0], arg2[1], arg2[2]);
printf("%p: %c %c %c\n", arg3, arg3[0], arg3[1], arg3[2]);
}
Swift:
let input0: String? = "Zero"
let input1: String? = "One"
let input2: String? = "Two"
let input3: String? = "Three"
multiString(input0, input1, input2, input3)
Results in:
0x101003170: T h r
0x101003170: T h r
0x101003170: T h r
0x101003170: T h r
It appears that there's a bug with how Swift handles multiple arguments.
I didn't find anything useful on if this is desired behaviour or just a bug.
The pragmatic solution would probably be to just have a proxy method like this, but you probably did something similar already.
func proxy(_ str: String?, _ functionToProxy: (UnsafePointer<UInt8>?) -> ()) {
if let str = str {
functionToProxy(str)
} else {
functionToProxy(nil)
}
}
proxy(input, test)
Did you test if it was working in Swift 2? They changed something maybe related in Swift 3:
https://github.com/apple/swift-evolution/blob/master/proposals/0055-optional-unsafe-pointers.md
Just to be clear, there is a workaround until Apple fixes this. Unwrap your optional Strings before passing them and everything will work fine.
var anOptional: String?
var anotherOptional: String?
func mySwiftFunc() {
let unwrappedA = anOptional!
let unwrappedB = anotherOptional!
myCStringFunc(unwrappedA, unwrappedB)
}
As mentioned in the comments, this is a clear bug in Swift.
Here's a workaround I'm using. If you can't trust Swift to convert the strings to pointers for you, then you've got to do it yourself.
Assuming C function defined as:
void multiString(const char *arg0, const char *arg1, const char *arg2);
Swift code:
func callCFunction(arg0: String?, arg1: String?, arg2: String?) {
let dArg0 = arg0?.data(using: .utf8) as NSData?
let pArg0 = dArg0?.bytes.assumingMemoryBound(to: Int8.self)
let dArg1 = arg1?.data(using: .utf8) as NSData?
let pArg1 = dArg1?.bytes.assumingMemoryBound(to: Int8.self)
let dArg2 = arg2?.data(using: .utf8) as NSData?
let pArg2 = dArg2?.bytes.assumingMemoryBound(to: Int8.self)
multiString(pArg1, pArg2, pArg3)
}
Warning:
Don't be tempted to put this in a function like:
/* DO NOT USE -- BAD CODE */
func ocstr(_ str: String?) -> UnsafePointer<Int8>? {
guard let str = str else {
return nil
}
let nsd = str.data(using: .utf8)! as NSData
//This pointer is invalid on return:
return nsd.bytes.assumingMemoryBound(to: Int8.self)
}
which would remove repeated code. This doesn't work because the data object nsd gets deallocated at the end of the function. The pointer is therefore not valid on return.

access element of fixed length C array in swift

I'm trying to convert some C code to swift.
(Why? - to use CoreMIDI in OS-X in case you asked)
The C code is like this
void printPacketInfo(const MIDIPacket* packet) {
int i;
for (i=0; i<packet->length; i++) {
printf("%d ", packet->data[i]);
}
}
And MIDIPacket is defined like this
struct MIDIPacket
{
MIDITimeStamp timeStamp;
UInt16 length;
Byte data[256];
};
My Swift is like this
func printPacketInfo(packet: UnsafeMutablePointer<MIDIPacket>){
// print some things
print("length", packet.memory.length)
print("time", packet.memory.timeStamp)
print("data[0]", packet.memory.data.1)
for i in 0 ..< packet.memory.length {
print("data", i, packet.memory.data[i])
}
}
But this gives a compiler error
error: type '(UInt8, UInt8, .. cut .. UInt8, UInt8, UInt8)'
has no subscript members
So how can I dereference the I'th element of a fixed size array?
in your case you could try to use something like this ...
// this is tuple with 8 Int values, in your case with 256 Byte (UInt8 ??) values
var t = (1,2,3,4,5,6,7,8)
t.0
t.1
// ....
t.7
func arrayFromTuple<T,R>(tuple:T) -> [R] {
let reflection = Mirror(reflecting: tuple)
var arr : [R] = []
for i in reflection.children {
// better will be to throw an Error if i.value is not R
arr.append(i.value as! R)
}
return arr
}
let arr:[Int] = arrayFromTuple(t)
print(arr) // [1, 2, 3, 4, 5, 6, 7, 8]
...
let t2 = ("alfa","beta","gama")
let arr2:[String] = arrayFromTuple(t2)
arr2[1] // "beta"
This was suggested by https://gist.github.com/jckarter/ec630221890c39e3f8b9
func printPacketInfo(packet: UnsafeMutablePointer<MIDIPacket>){
// print some things
print("length", packet.memory.length)
print("time", packet.memory.timeStamp)
let len = Int(packet.memory.length)
withUnsafePointer(&packet.memory.data) { p in
let p = UnsafeMutablePointer<UInt8>(p)
for i:Int in 0 ..< len {
print(i, p[i])
}
}
}
This is horrible - I hope the compiler turns this nonsense into some good code
The error message is a hint: it shows that MIDIPacket.data is imported not as an array, but as a tuple. (Yes, that's how all fixed length arrays import in Swift.) You seem to have noticed this in the preceding line:
print("data[0]", packet.memory.data.1)
Tuples in Swift are very static, so there isn't a way to dynamically access a tuple element. Thus, in some sense the only "safe" or idiomatic way to print your packet (in the way that you're hinting at) would be 256 lines of code (or up to 256, since the packet's length field tells you when it's safe to stop):
print("data[1]", packet.memory.data.2)
print("data[2]", packet.memory.data.3)
print("data[3]", packet.memory.data.4)
/// ...
print("data[254]", packet.memory.data.255)
print("data[255]", packet.memory.data.256)
Clearly that's not a great solution. Using reflection, per user3441734's answer, is one (cumbersome) alternative. Unsafe memory access, per your own answer (via jckarter), is another (but as the name of the API says, it's "unsafe"). And, of course, you can always work with the packet through (Obj)C.
If you need to do something beyond printing the packet, you can extend the UnsafePointer-based solution to convert it to an array like so:
extension MIDIPacket {
var dataBytes: [UInt8] {
mutating get {
return withUnsafePointer(&data) { tuplePointer in
let elementPointer = UnsafePointer<UInt8>(tuplePointer)
return (0..<Int(length)).map { elementPointer[$0] }
}
}
}
}
Notice that this uses the packet's existing length property to expose an array that has only as many valid bytes as the packet claims to have (rather than filling up the rest of a 256-element array with zeroes). This does allocate memory, however, so it might not be good for the kinds of real-time run conditions you might be using CoreMIDI in.
Should this:
for i in 0 ..< packet.memory.length
Be this?
for i in 0 ..< packet.memory.data.length