В любом случае, чтобы имитировать код [NSString stringWithFormat:@"%p", myVar]
на новом быстром языке?
Например:
let str = "A String"
println(" str value \(str) has address: ?")
В любом случае, чтобы имитировать код [NSString stringWithFormat:@"%p", myVar]
на новом быстром языке?
Например:
let str = "A String"
println(" str value \(str) has address: ?")
Теперь это часть стандартной библиотеки: 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 используйте withUnsafePointer
:
var str = "A String"
withUnsafePointer(to: &str) {
print(" str value \(str) has address: \($0)")
}
print(Unmanaged.passUnretained(someVar).toOpaque())
Печатает адрес памяти someVar. (спасибо @Ying)
print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Печатает адрес памяти someVar.
Обратите внимание, что этот ответ был довольно старым. Многие из описанных методов больше не работают. В частности, .core
невозможно получить доступ.
Однако ответ @drew правильный и простой:
Теперь это часть стандартной библиотеки: unsafeAddressOf.
Итак, ответ на ваши вопросы:
println(" str value \(str) has address: \(unsafeAddressOf(str))")
Вот оригинальный ответ, который был отмечен правильно (для потомства/вежливости):
Swift "скрывает" указатели, но они все еще существуют под капотом. (потому что это требует времени выполнения, а также по причинам совместимости с Objc и C)
Однако есть несколько вещей, которые нужно знать, но сначала как напечатать адрес памяти строки Swift?
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
Это будет в стеке, потому что строка создается во время выполнения
ПРИМЕЧАНИЕ:.core._baseAddress не документирован, я нашел его в инспекторе переменных, и он может быть скрыт в будущем
_baseAddress недоступен для всех типов, вот еще один пример с CInt
var testNumber : CInt = 289
takesInt(&testNumber)
Где takesInt
- вспомогательная C-функция, подобная этой
void takesInt(int *intptr)
{
printf("%p", intptr);
}
На стороне Swift эта функция takesInt(intptr: CMutablePointer<CInt>)
, поэтому для CInt требуется CMutablePointer, и вы можете получить ее с помощью & varname
Функция печатает 0x7fff5fbfed98
, а по этому адресу памяти вы найдете 289 (в шестнадцатеричной нотации). Вы можете изменить его содержимое с помощью *intptr = 123456
Теперь, некоторые другие вещи, чтобы знать.
Строка, в swift, является примитивным типом, а не объектом.
CInt - тип Swift, сопоставленный с типом C int.
Если вы хотите адрес памяти объекта, вам нужно сделать что-то другое.
Swift имеет некоторые типы указателей, которые можно использовать при взаимодействии с 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 (это может быть сделано даже без параметров)
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
( Изменить: 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
является структурой. Поэтому, если s
присваивается другой переменной s2
, значение будет скопировано и возвращаемый адрес для s2
будет другим.
Как и в Objective-C, существует два разных адреса, связанных с o
. Первый - это местоположение объекта, второе - местоположение ссылки (или указателя) на объект.
Да, это означает, что содержимое адреса 0x7fff5fbfe658 - это номер 0x6100000011d0, который может сообщить нам отладчик:
(lldb) x/g 0x7fff5fbfe658
0x7fff5fbfe658: 0x00006100000011d0
Итак, за исключением строк, являющихся структурами, внутренне это все в значительной степени работает так же, как в (Objective-) C.
(Текущий с 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
*/
(Gist)
В Swift мы имеем дело со значениями типов (структур) или ссылочными типами (классами). При выполнении:
let n = 42 // Int is a structure, i.e. value type
Некоторая память выделяется по адресу X, и по этому адресу мы найдем значение 42. Doing &n
создает указатель, указывающий на адрес X, поэтому &n
сообщает нам, где находится 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()
Память выделяется в двух местах:
Как сказано, классы являются ссылочными типами: поэтому значение 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) { $0.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
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
Если вы просто хотите увидеть это в отладчике и ничего не делать с ним, нет необходимости фактически получать указатель Int
. Чтобы получить строковое представление адреса объекта в памяти, просто используйте что-то вроде этого:
public extension NSObject { // Extension syntax is cleaner for my use. If your needs stem outside NSObject, you may change the extension target or place the logic in a global function
public var pointerString: String {
return String(format: "%p", self)
}
}
Пример использования:
print(self.pointerString, "Doing something...")
// Prints like: 0x7fd190d0f270 Doing something...
Кроме того, помните, что вы можете просто распечатать объект, не переопределяя его description
, и он будет показывать свой адрес указателя рядом с более описательным (если он является загадочным) текстом.
print(self, "Doing something else...")
// Prints like: <MyModule.MyClass: 0x7fd190d0f270> Doing something else...
// Sometimes like: <_TtCC14__lldb_expr_668MyModule7MyClass: 0x7fd190d0f270> Doing something else...
Другие ответы в порядке, хотя я искал способ получить адрес указателя как целое число:
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 обеспечивает использование только для типа класса.
Ответ @nschum обеспечивает может быть только для типа структуры.
Однако, если вы используете второй метод для получения адреса массива с элементом типа значения. Swift скопирует весь массив, потому что в массиве Swift используется копирование на запись, и Swift не может убедиться, что он ведет себя таким образом, как только он передает управление 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, я хотел получить адрес как целое число. В частности, мне нужен адрес объекта Thread для использования в качестве идентификатора потока в модуле ведения журнала диагностики, в ситуациях, когда имя потока не было доступно.
Основываясь на коде Чарли Монро, вот что я до сих пор придумал. Но будьте осторожны, я очень новичок в 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. Операция modulo в последнем выражении преобразует ее в 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)
}
Просто используйте это:
print(String(format: "%p", object))
Это, конечно, не самый быстрый или безопасный способ. Но это работает для меня. Это позволит любому подмножеству 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
private func pointer(_ object: AnyObject?) -> String {
guard let object = object else { return "nil" }
let opaque: UnsafeMutableRawPointer = Unmanaged.passUnretained(object).toOpaque()
return String(describing: opaque)
}
private func address<T: AnyObject>(o: T) -> String{
let addr = unsafeBitCast(o, to: Int.self)
return NSString(format: "%p", addr) as String
}
func testPrintMemoryAddr() {
var str = "A String"
print("Way1 str \(self.pointer(str as AnyObject))")
let strPointer = String.init(format: "%p", str)
print("Way2 str \(strPointer)")
let strPointer1 = address(o: str as AnyObject)
print("Way3 str \(strPointer)")
}
Я предпочитаю второй метод.