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