Have a look at this refactored version (I'm using int32 elements to keep output compact):
Some infrastructure
typealias ElementType = Int32
typealias ArrayType = Array<ElementType>
let element: ElementType = 0x11223344
let headerSize = 32
func isStackMemory(_ ptr: UnsafeRawPointer) -> Bool {
let stackBase = pthread_get_stackaddr_np(pthread_self())
let stackSize = pthread_get_stacksize_np(pthread_self())
return ptr <= stackBase && ptr >= stackBase - stackSize
}
enum MemoryType: String {
case stack = "on stack", heap = "on heap", other = "other memory (global?)"
init(_ ptr: UnsafeRawPointer) {
// TODO: correct heap memory determination
if isStackMemory(ptr) {
self = .stack
} else {
self = .other
}
}
}
func dumpHex(_ title: String, _ ptr: UnsafeRawPointer, _ size: Int, _ headerSize: Int = 0) {
var size = size
var ptr = ptr
let mallocSize = malloc_size(ptr - headerSize)
if mallocSize != 0 {
let mallocBlock = ptr - headerSize
print("\(title), \(mallocBlock) + \(headerSize) = \(ptr) (\(MemoryType.heap.rawValue)), size: \(headerSize) + \(mallocSize - headerSize) = \(mallocSize) -> ")
size = mallocSize
ptr = mallocBlock
} else {
print("\(title), \(ptr) (\(MemoryType(ptr).rawValue)), showing size: \(size) -> ")
}
let v = ptr.assumingMemoryBound(to: UInt8.self)
for i in 0 ..< size {
if i != 0 && (i % 32) == 0 {
print()
}
print(String(format: "%02x ", v[i]), terminator: "")
}
print()
}
Your code changed a bit:
func mutableRawPointer(_ p: UnsafeMutableRawPointer) {
dumpHex("mutableRawPointer", p, 8, headerSize)
}
func arrayPointer(_ p: UnsafeMutablePointer<ArrayType>) {
dumpHex("arrayPointer", p, 8, headerSize)
}
func genericTypedPointer<T>(_ p: UnsafeMutablePointer<T>) {
dumpHex("genericTypedPointer", p, 8, headerSize)
}
func forcedTypedPointer<FT>(_ title: String, _ : FT, _ p: UnsafeMutablePointer<FT>, _ headerSize: Int = 0) {
dumpHex(title, p, 8, headerSize)
}
func test() {
var array = ArrayType(repeating: element, count: 3)
dumpHex("duming array", &array, 8, headerSize)
// duming array, 0x0000600000c102a0 + 32 = 0x0000600000c102c0 (on heap), size: 32 + 16 = 48 ->
// 68 d4 3b f5 01 00 00 00 03 00 00 00 04 00 00 00 03 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00
// 44 33 22 11 44 33 22 11 44 33 22 11 00 00 00 00
mutableRawPointer(&array)
// mutableRawPointer, 0x0000600000c102a0 + 32 = 0x0000600000c102c0 (on heap), size: 32 + 16 = 48 ->
// 68 d4 3b f5 01 00 00 00 03 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00
// 44 33 22 11 44 33 22 11 44 33 22 11 00 00 00 00
arrayPointer(&array)
// arrayPointer, 0x000000016fdfe940 (on stack), showing size: 8 ->
// a0 02 c1 00 00 60 00 00
genericTypedPointer(&array)
// genericTypedPointer, 0x0000600000c102a0 + 32 = 0x0000600000c102c0 (on heap), size: 32 + 16 = 48 ->
// 68 d4 3b f5 01 00 00 00 03 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00
// 44 33 22 11 44 33 22 11 44 33 22 11 00 00 00 00
forcedTypedPointer("forcedTypedPointer element", ElementType(), &array, headerSize)
// forcedTypedPointer element, 0x0000600000c102a0 + 32 = 0x0000600000c102c0 (on heap), size: 32 + 16 = 48 ->
// 68 d4 3b f5 01 00 00 00 03 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00
// 44 33 22 11 44 33 22 11 44 33 22 11 00 00 00 00
forcedTypedPointer("forcedTypedPointer array", array, &array)
// forcedTypedPointer array, 0x000000016fdfe940 (on stack), showing size: 8 ->
// a0 02 c1 00 00 60 00 00
}
test()
This drilles into the memory and shows the whole memory block (if available) along with some details (whether it's on heap or stack, etc).
Note how in some cases you are viewing the array contents, while in other cases you are viewing the memory corresponding to the Array struct (8 bytes holding the pointer to array block). The memory is layout out in little endian form, so this:
// a0 02 c1 00 00 60 00 00
treated as 0000600000c102a0 which matches the memory address of array block above.
68 d4 3b f5 01 00 00 00 03 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00
|-ISA-------------------|-REF-COUNTS------------|-CURRENT-SIZE----------|-CAPACITY?-------------|
44 33 22 11 44 33 22 11 44 33 22 11 00 00 00 00
|-ELEMENT-0-|-ELEMENT-1-|-ELEMENT-2-|-FREE-SPACE|
In practical terms, if you are after the pointer to the contents (I assume this is the one you want) – pick mutableRawPointer, genericTypedPointer or forcedTypedPointer+element, while if you are after the pointer to array struct itself (which is very rarely needed) then choose arrayPointer, or forcedTypedPointer+array.