Печать адреса переменной памяти в swift



есть ли в любом случае, чтобы имитировать [NSString stringWithFormat:@"%p", myVar] код на новом языке swift ?



например:



let str = "A String"
println(" str value (str) has address: ?")
767   15  

15 ответов:

Swift 2

теперь это часть стандартной библиотеки: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

для Swift 3, Используйте withUnsafePointer:

var str = "A String"
withUnsafePointer(to: &str) {
    print(" str value \(str) has address: \()")
}

Swift 3.1:

print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())

выводит адрес памяти someVar.


Swift 4:

print(Unmanaged.passUnretained(someVar).toOpaque())

выводит адрес памяти someVar. (спасибо @Ин)


обратите внимание, что этот ответ был довольно старый. Многие из методов, которые он описывает, больше не работают. В частности .core не обращались.

однако ответ @drew правильный и простой:

теперь это часть стандартной библиотеки: unsafeAddressOf.

Итак, ответ на ваши вопросы:

println(" str value \(str) has address: \(unsafeAddressOf(str))")

вот оригинальный ответ, который был отмечен правильно (для потомство/вежливость):

Swift "скрывает" указатели, но они все еще существуют под капотом. (потому что среда выполнения нуждается в этом, и по причинам совместимости с Objc и C)

есть несколько вещей, чтобы знать, однако, но сначала, как напечатать адрес памяти быстрой строки?

    var aString : String = "THIS IS A STRING"
    NSLog("%p", aString.core._baseAddress)  // _baseAddress is a COpaquePointer
   // example printed address 0x100006db0

это печатает адрес памяти строки, Если вы откроете XCode - > Debug Workflow - > View Memory и перейдете к печатному адресу, вы увидите необработанные данные строки. Поскольку это строковый литерал, это адрес памяти внутри хранилища двоичного файла (не стека или кучи).

однако, если у вас

    var aString : String = "THIS IS A STRING" + "This is another String"
    NSLog("%p", aString.core._baseAddress)

    // example printed address 0x103f30020

это будет в стеке, потому что строка создается во время выполнения

Примечание: .ядро._baseAddress не задокументирован, я нашел его в инспекторе переменных, и он может быть скрыт в будущем

_baseAddress доступен не на всех типах, вот еще один пример с а Кинт

    var testNumber : CInt = 289
    takesInt(&testNumber)

здесь takesInt это вспомогательная функция C, как это

void takesInt(int *intptr)
{
    printf("%p", intptr);
}

на стороне Swift эта функция takesInt(intptr: CMutablePointer<CInt>), поэтому он принимает CMutablePointer к CInt, и вы можете получить его с &varname

печать функция 0x7fff5fbfed98, по этому адресу памяти вы найдете 289 (в шестнадцатеричной системе счисления). Вы можете изменить его содержимое с помощью *intptr = 123456

теперь, некоторые другие вещи, чтобы знать.

строки в Swift, это примитивный тип, а не объект.
CInt-это быстрый тип, сопоставленный с типом C int.
Если вы хотите адрес памяти объекта, вы должны сделать что-то другое.
Свифт имеет некоторые типы указателей, которые могут быть использованы при взаимодействии с C, и вы можете прочитать о них здесь: Типы Указателей Swift
Кроме того, вы можете узнать больше о них, исследуя их объявление (cmd+нажмите на тип), чтобы понять, как преобразовать тип указателя в еще один

    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 это вспомогательная функция C, которую я создал, с этой реализацией

void printptr(void ** ptr)
{
    printf("%p", *ptr);
}

опять же, пример напечатанного адреса:0x6000000530b0, и если вы пройдете через инспектор памяти, вы найдете свою NSString

одна вещь, которую вы можете сделать с указателями в Swift (это можно сделать даже с параметрами inout)

    func playWithPointer (stringa :AutoreleasingUnsafePointer<NSString>) 
    {
        stringa.memory = "String Updated";
    }

    var testString : NSString = "test string"
    println(testString)
    playWithPointer(&testString)
    println(testString)

или, взаимодействуя с 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

чтобы получить (куча) адрес объекта

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 теперь включает аналогичную функцию под названием unsafeAddressOf.)

в Objective-C это будет [NSString stringWithFormat:@"%p", o].

o - это ссылка на экземпляр. Так что если o присваивается другой переменной o2, возвращенный адрес o2 будет то же самое.

это не относится к структурам (включая String) и примитивные типы (такие как Int), потому что они живут прямо на стеке. Но мы можем получить местоположение в стеке.

чтобы получить адрес (стека) структуры, встроенного типа или ссылки на объект

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

в Objective-C это будет [NSString stringWithFormat:@"%p", &o] или [NSString stringWithFormat:@"%p", &i].

s - это struct. Так что если s присваивается другой переменной s2, значение будет скопировано и возвращенный адрес для s2 будут разные.

как он сочетается (указатель напомним)

как в Objective-C, есть два разных адреса, связанные с o. Первый-это расположение объекта, второй-расположение ссылки (или указателя) на объект.

Да, это означает, что содержимое адреса 0x7fff5fbfe658 является числом 0x6100000011d0, как отладчик может сказать нам:

(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0

Итак, за исключением строк, являющихся структурами, внутренне это все в значительной степени работает так же, как и в (Цель -) С.

(текущий по состоянию на Xcode 6.3)

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
*/

(суть)


в Swift мы имеем дело либо с типами значений (структурами), либо с ссылочными типами (классами). При выполнении:

let n = 42 // Int is a structure, i.e. value type

некоторая память выделяется по адресу X, и по этому адресу мы найдем значение 42. Делать &n создает указатель, указывающий на адрес X, поэтому &n говорит нам, где есть.

(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

когда делать:

class C { var foo = 42, bar = 84 }
var c = C()

память выделяется в двух местах:

  • по адресу Y, где находятся данные экземпляра класса и
  • по адресу X, где находится ссылка на экземпляр класса.

как уже было сказано, классы являются ссылочными типами: так что значение c находится по адресу X, по которому мы найдем значение Y. А по адресу Y + 16 найдем foo а по адресу Y + 24 мы найдем bar (при + 0 и + 8 мы будем найти тип данных и количество ссылок, я не могу сказать вам больше об этом...).

(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 - это 42 (foo) и 0x54 составляет 84 (бар).

в обоих случаях, используя &n или &c даст нам адрес X. Для типов значений, это то, что мы хотим, но не для ссылочных типов.

когда делать:

let referencePointer = UnsafeMutablePointer<C>(&c)

мы создаем указатель на ссылку, т. е. указатель, который указывает на адрес X. То же самое, когда используя 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)

теперь, когда у нас есть лучшее понимание того, что происходит под капотом, и что мы теперь, когда по адресу X мы найдем адрес Y( который мы хотим), мы можем сделать следующее, чтобы получить его:

let addressY = unsafeBitCast(c, to: Int.self)

проверка:

(lldb) frame variable addressY -f hex
(Int) addressY = 0x0000000101b2fd20
(lldb) frame variable c
(testmem.C) c = 0x0000000101b2fd20 (foo = 42, bar = 84)

есть и другие способы сделать это:

let addressY1 = Int(bitPattern: Unmanaged.passUnretained(c).toOpaque())
let addressY2 = withUnsafeMutableBytes(of: &c) { .load(as: Int.self) }

toOpaque() на самом деле называет unsafeBitCast(c, to: UnsafeMutableRawPointer.self).

я надеюсь, что это помогло... для меня так и было .

Ссылка Типа:

  • имеет смысл получить адрес памяти ссылочного типа, поскольку он представляет идентификатор.
  • === оператор идентификации используется для проверки 2 объектов, указывающих на одну и ту же ссылку.
  • использовать ObjectIdentifier чтобы получить адрес памяти

код:

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

Значение Типа:

  • необходимость получения адреса памяти типа значения не имеет большого значения (так как это значение) и акцент будет больше сделан на равенстве ценности.

если вы просто хотите увидеть это в отладчике и не делать ничего другого с ним, нет необходимости на самом деле получить

Swift 4

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)
    }
}

использование:

print("FileManager.default: \(String.pointer(FileManager.default))")
// FileManager.default: 0x00007fff5c287698

print("nil: \(String.pointer(nil))")
// nil: nil

другие ответы в порядке, хотя я искал способ получить адрес указателя в виде целого числа:

let ptr = unsafeAddressOf(obj)
let nullPtr = UnsafePointer<Void>(bitPattern: 0)

/// This gets the address of pointer
let address = nullPtr.distanceTo(ptr) // This is Int

просто небольшое продолжение.

ответ @Drew provide может использоваться только для типа класса.
Ответ @nschum provide может быть только для типа структуры.

однако, если вы используете второй метод для получения адреса массива с элементом типа значения. Swift скопирует весь массив, потому что в Swift массив копируется при записи, и Swift не может убедиться, что он ведет себя таким образом, как только он передаст управление на C/C++ (что является триггером с помощью & получить адрес). И если вы используете первый метод вместо этого, он будет автоматически конвертировать Array до NSArray что, безусловно, то, что мы не хотим.

таким образом, самый простой и унифицированный способ, который я нашел, - это использование инструкции lldb frame variable -L yourVariableName.

или вы можете объединить их ответы:

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
}

Это для Swift 3.

Как @CharlieMonroe я хотел получить адрес в виде целого числа. В частности, мне нужен адрес объекта потока для использования в качестве идентификатора потока в модуле ведения журнала диагностики для ситуаций, когда имя потока недоступно.

основан на коде Чарли Монро, вот что я придумал до сих пор. Но будьте осторожны, я очень новичок в Swift, это может быть неправильно ...

  // 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

последнее утверждение есть, потому что без него я получал адреса, такие как 0x60000007DB3F. операция по модулю в последнем операторе преобразует это в 0x7DB3F.

мое решение на Swift 3

extension MyClass: CustomStringConvertible {
    var description: String {
        return "<\(type(of: self)): 0x\(String(unsafeBitCast(self, to: Int.self), radix: 16, uppercase: false))>"
    }
}

этот код создает описание как описание по умолчанию <MyClass: 0x610000223340>

в Swift4 о массиве:

    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)
    }

это, конечно, не самый быстрый и безопасный способ сделать это. Но это работает для меня. Это позволит любому подклассу nsobject принять это свойство.

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

просто использовать это:

print(String(format: "%p", object))

Comments

    Ничего не найдено.