Czy w ogóle istnieje możliwość symulacji [NSString stringWithFormat:@"%p", myVar]
, z Objective-C, w nowym języku Swift?
Na przykład:
let str = "A String"
println(" str value \(str) has address: ?")
swift
debugging
memory-address
apouche
źródło
źródło
[NSString stringWithFormat:@"%p", myVar]
,myVar
musi być wskaźnikiem. W kodzie Swiftstr
nie jest wskaźnikiem. Więc porównanie nie ma zastosowania.Odpowiedzi:
Szybki 2
Jest obecnie częścią standardowej biblioteki:
unsafeAddressOf
.Szybki 3
W przypadku Swift 3 użyj
withUnsafePointer
:źródło
withUnsafePointer
skutkujecannot pass immutable value as inout argument
błędem.print(self.description)
wydruki<MyViewController: 0x101c1d580>
, używamy go jako odniesienia.var mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }
wydruki,0x16fde4028
które są wyraźnie innym adresem. Czy ktoś może wyjaśnić, dlaczego?0x101c1d580
zgodnie z oczekiwaniami:print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
UnsafePointer
jest strukturą, więc aby wydrukować adres, na który wskazuje (a nie samą strukturę), musisz wydrukowaćString(format: "%p", $0.pointee)
!Uwaga: dotyczy to typów referencyjnych.
Swift 4/5:
Drukuje adres pamięci someVar. (dzięki @Ying)
Swift 3.1:
Drukuje adres pamięci someVar.
źródło
print(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Unmanaged
można to zrobić tak:print(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque())
.Unmanaged.passUnretained(someVar).toOpaque()
(nie ma potrzeby ogólnej specyfikacji)debugDescription
na końcu tego.Zauważ, że ta odpowiedź była dość stara. Wiele metod, które opisuje, już nie działa. W szczególności
.core
nie można już uzyskać do nich dostępu.Jednak odpowiedź @ drew jest poprawna i prosta:
Tak więc odpowiedź na Twoje pytania brzmi:
Oto oryginalna odpowiedź, która została oznaczona jako poprawna (dla potomności / grzeczności):
Szybkie „chowa” wskazówki, ale nadal istnieją pod maską. (ponieważ środowisko wykonawcze tego potrzebuje i ze względu na zgodność z Objc i C)
Jest jednak kilka rzeczy, które należy wiedzieć, ale najpierw jak wydrukować adres pamięci Swift String?
Spowoduje to wyświetlenie adresu pamięci ciągu, jeśli otworzysz XCode -> Debug Workflow -> View Memory i przejdziesz do wydrukowanego adresu, zobaczysz nieprzetworzone dane ciągu. Ponieważ jest to literał łańcuchowy, jest to adres pamięci wewnątrz magazynu pliku binarnego (nie stosu ani sterty).
Jednak jeśli to zrobisz
Będzie to na stosie, ponieważ ciąg jest tworzony w czasie wykonywania
UWAGA: .core._baseAddress nie jest udokumentowany, znalazłem go w inspektorze zmiennych i może być ukryty w przyszłości
_baseAddress nie jest dostępny we wszystkich typach, tutaj inny przykład z CInt
Gdzie
takesInt
jest taka funkcja pomocnicza C.Po stronie Swift ta funkcja jest
takesInt(intptr: CMutablePointer<CInt>)
więc pobiera CMutablePointer do CInt i możesz ją uzyskać za pomocą & varnameFunkcja drukuje
0x7fff5fbfed98
, a pod tym adresem pamięci znajduje się 289 (w notacji szesnastkowej). Możesz zmienić jego zawartość za pomocą*intptr = 123456
A teraz kilka innych rzeczy, które warto wiedzieć.
String w swift jest typem pierwotnym, a nie obiektem.
CInt jest typem Swift zamapowanym na typ int C.
Jeśli chcesz mieć adres pamięci obiektu, musisz zrobić coś innego.
Swift ma kilka typów wskaźników, których można używać podczas interakcji z C, i możesz o nich przeczytać tutaj: Typy wskaźników Swift
Ponadto możesz dowiedzieć się więcej o nich, badając ich deklarację (cmd + kliknij typ), aby zrozumieć, jak konwertować rodzaj wskaźnika do innego
printptr
jest funkcją pomocniczą języka C, którą stworzyłem, z tą implementacjąPonownie, przykład wydrukowanego adresu:
0x6000000530b0
a jeśli przejdziesz przez inspektora pamięci, znajdziesz swój NSStringJedna rzecz, którą możesz zrobić ze wskaźnikami w Swift (można to nawet zrobić z parametrami inout)
Lub, wchodząc w interakcję z Objc / c
źródło
Aby uzyskać adres (sterty) obiektu
( Edycja: Swift 1.2 zawiera teraz podobną funkcję o nazwie
unsafeAddressOf
.)W Objective-C tak będzie
[NSString stringWithFormat:@"%p", o]
.o
jest odniesieniem do instancji. Więc jeślio
zostanie przypisana do innej zmiennejo2
, zwracany adreso2
będzie taki sam.Nie dotyczy to struktur (w tym
String
) i typów pierwotnych (takich jakInt
), ponieważ te żyją bezpośrednio na stosie. Ale możemy pobrać lokalizację na stosie.Aby uzyskać adres (stosu) struktury, typ wbudowany lub odwołanie do obiektu
W Objective-C byłoby to
[NSString stringWithFormat:@"%p", &o]
lub[NSString stringWithFormat:@"%p", &i]
.s
jest strukturą. Jeśli więcs
zostanie przypisana do innej zmiennejs2
, wartość zostanie skopiowana, a zwracany adres dlas2
będzie inny.Jak to pasuje do siebie (podsumowanie wskaźnika)
Podobnie jak w Objective-C, istnieją dwa różne adresy powiązane z
o
. Pierwsza to lokalizacja obiektu, druga to lokalizacja odniesienia (lub wskaźnika) do obiektu.Tak, to znaczy, że zawartość adresu 0x7fff5fbfe658 to numer 0x6100000011d0, ponieważ debugger może nam powiedzieć:
Tak więc, z wyjątkiem łańcuchów będących strukturami, wewnętrznie to wszystko działa prawie tak samo jak w (Objective-) C.
(Aktualne od Xcode 6.3)
źródło
TL; DR
( Streszczenie )
W Swift mamy do czynienia z typami wartości (strukturami) lub typami referencyjnymi (klasami). Robiąc:
Część pamięci jest alokowana pod adresem X i pod tym adresem znajdziemy wartość 42. Doing
&n
tworzy wskaźnik wskazujący na adres X, a zatem&n
mówi nam, gdzien
się znajduje.Robiąc:
Pamięć jest przydzielana w dwóch miejscach:
Jak już powiedziano, klasy są typami referencyjnymi: więc wartość
c
znajduje się pod adresem X, pod którym znajdziemy wartość Y. A pod adresem Y + 16 znajdziemy,foo
a pod adresem Y + 24 znajdziemybar
( na + 0 i + 8 znajdziemy dane typu i liczbę referencji, nie mogę powiedzieć więcej na ten temat ...).0x2a
wynosi 42 (foo) i0x54
84 (bar).W obu przypadkach użycie
&n
lub&c
da nam adres X. W przypadku typów wartości właśnie tego chcemy, ale nie w przypadku typów referencyjnych.Robiąc:
Tworzymy wskaźnik na referencję, tj. Wskaźnik, który wskazuje na adres X. To samo przy używaniu
withUnsafePointer(&c) {}
.Teraz, gdy mamy lepsze zrozumienie tego, co dzieje się pod maską, i że teraz pod adresem X znajdziemy adres Y (który jest tym, którego potrzebujemy), możemy wykonać następujące czynności, aby go uzyskać:
Weryfikacja:
Można to zrobić na inne sposoby:
toOpaque()
faktycznie dzwoniunsafeBitCast(c, to: UnsafeMutableRawPointer.self)
.Mam nadzieję, że to pomogło ... pomogło mi 😆.
źródło
MemoryLocation
tworzy 2 różne adresy.Typy referencyjne:
===
Operator tożsamości służy do sprawdzania, czy 2 obiekty wskazują na to samo odniesienie.ObjectIdentifier
aby uzyskać adres pamięciKod:
Typy wartości:
źródło
Po prostu użyj tego:
źródło
MyClass?
niezgodności „ ” z CVarArg, możesz to zrobićextension Optional : CVarArg { }
. W przeciwnym razie wydaje się, że wypisuje adresy bez „niebezpiecznego” szaleństwa innych odpowiedzi.var _cVarArgEncoding: [Int]
onCVarArg
. Nie jest jasne, jak należy to wdrożyć.Jeśli chcesz po prostu zobaczyć to w debugerze i nie robić z tym nic więcej, nie ma potrzeby pobierania
Int
wskaźnika. Aby uzyskać ciąg znaków reprezentujący adres obiektu w pamięci, użyj czegoś takiego:Przykładowe użycie:
Ponadto pamiętaj, że możesz po prostu wydrukować obiekt bez nadpisywania jego
description
, a on pokaże swój adres wskaźnika obok bardziej opisowego (jeśli często tajemniczego) tekstu.źródło
Szybki 5
Stosowanie:
źródło
Unmanaged.passUnretained(myObject).toOpaque()
zamiast tego działa prawidłowo.AnyObject
parametr. WolałbymAny
jako typ wejścia.W Swift4 o Array:
źródło
self?.array
.Pozostałe odpowiedzi są w porządku, chociaż szukałem sposobu na uzyskanie adresu wskaźnika jako liczby całkowitej:
Tylko mała kontynuacja.
źródło
Odpowiedzi @Drew można użyć tylko dla typu klasy.
Odpowiedź @nschum może dotyczyć tylko typu struktury.
Jeśli jednak używasz drugiej metody, aby uzyskać adres tablicy z elementem typu wartości. Swift skopiuje całą tablicę, ponieważ w Swift tablica jest kopiowana przy zapisie i Swift nie może upewnić się, że zachowa się w ten sposób po przekazaniu kontroli do C / C ++ (co jest wyzwalane przez użycie
&
do uzyskania adresu). A jeśli zamiast tego użyjesz pierwszej metody, zostanie ona automatycznie przekonwertowanaArray
naNSArray
coś, czego z pewnością nie chcemy.Najprostszym i najbardziej ujednoliconym sposobem, jaki znalazłem, jest użycie instrukcji lldb
frame variable -L yourVariableName
.Lub możesz połączyć ich odpowiedzi:
źródło
To jest dla Swift 3.
Podobnie jak @CharlieMonroe, chciałem uzyskać adres jako liczbę całkowitą. W szczególności chciałem, aby adres obiektu Thread był używany jako identyfikator wątku w module rejestrowania diagnostycznego w sytuacjach, w których nazwa wątku nie była dostępna.
W oparciu o kod Charliego Monroe, oto co wymyśliłem do tej pory. Ale uwaga, jestem nowy w Swift, to może nie być poprawne ...
Ostatnia instrukcja jest tam, ponieważ bez niej otrzymywałem adresy takie jak 0x60000007DB3F. Operacja modulo w ostatniej instrukcji konwertuje to na 0x7DB3F.
źródło
Moje rozwiązanie w Swift 3
ten kod tworzy opis jak domyślny opis
<MyClass: 0x610000223340>
źródło
Z pewnością nie jest to najszybszy ani najbezpieczniejszy sposób. Ale to działa dla mnie. Pozwoli to każdej podklasie nsobject na przyjęcie tej właściwości.
źródło