可変メモリアドレスを迅速に印刷する


165

とにかく[NSString stringWithFormat:@"%p", myVar]、新しいSwift言語でObjective-Cからをシミュレートすることはありますか?

例えば:

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

2
では[NSString stringWithFormat:@"%p", myVar]myVarポインタでなければなりません。あなたのSwiftコードでstrは、ポインタではありません。したがって、比較は適用されません。
user102008 2014

5
少なくともこれを入力しているときは、上記の2つのコメントは正しくないことに注意してください。
Ben Leggiero 16

回答:


112

スウィフト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

スウィフト3

Swift 3の場合withUnsafePointer

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

2
unsafeAddressOf()は(@Nickが以下に指摘するように)クラス型に対してのみ機能します。したがって、この回答はFoundationがインポートされ、StringがNSStringにブリッジされている場合にのみ機能します。プレーンなSwiftでは、Stringは値の型であり、unsafeAddressOfを使用してそのアドレスを取得することはできません(試行するとコンパイルエラーが発生します)。
Stephen Schaub

29
Swift 3 で不変値のアドレスを印刷したい場合はどうすればよいですか?withUnsafePointerで結果cannot pass immutable value as inout argumentエラー。
Alexander Vasenin

12
それは受け入れられ、最も高い投票数の回答ですが、それでも間違った結果を出します。例:print(self.description)prints <MyViewController: 0x101c1d580>、参照として使用します。明らかに異なるアドレスをvar mutableSelf = self; withUnsafePointer(to: &mutableSelf) { print(String(format: "%p", $0)) }印刷0x16fde4028します。なぜ誰かが説明できますか?
Alexander Vasenin 2017

4
ところで、これ0x101c1d580は期待どおりに印刷されます:print(String(format: "%p", unsafeBitCast(self, to: Int.self)))
Alexander Vasenin 2017

8
@nygあなたの答えは私に実際のエラー原因の手がかりを与えました:UnsafePointer構造体なので、それが指しているアドレスを(それ自体ではなく)印刷するには、印刷する必要がありますString(format: "%p", $0.pointee)
Alexander Vasenin 2017

213

注:これは参照タイプ用です。

Swift 4/5:

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

someVarのメモリアドレスを出力します。(@Yingに感謝)


Swift 3.1:

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

someVarのメモリアドレスを出力します。



2
Xcode 8.2.1のオートコレクトがそれを今に伝えていますprint(Unmanaged<AnyObject>.passUnretained(someVar as AnyObject).toOpaque())
Jeff

2
これは、someVarがオブジェクトである場合にのみ当てはまります。someVarが構造体などの値型である場合、実行されるたびに異なるアドレスが与えられます。
OutOnAWeekend 2017

3
@OutOnAWeekendそのとおりです。おそらく、構造体が引数として渡されるときにコピーされるためです。使用Unmanaged方法は次のとおりprint(Unmanaged<AnyObject>.fromOpaque(&myStruct).toOpaque())です。
nyg 2017

1
Swift 4以降、この呪文を印刷することもできました- Unmanaged.passUnretained(someVar).toOpaque()(一般的な仕様は必要ありません)
Ying

2
Swift 4の答えは完璧です。印刷せずに文字列表現も取得したい場合はdebugDescription、最後に追加することをお勧めします。
Patrick

51

この答えはかなり古いことに注意してください。それが説明するメソッドの多くはもはや機能しません。具体的に.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>)なので、CMutablePointerをCIntに渡し、&varnameで取得できます。

関数は0x7fff5fbfed98、このメモリアドレスで289を出力します(16進表記)。あなたはその内容を変更することができます*intptr = 123456

さて、他に知っておくべきことがいくつかあります。

文字列は、迅速に言えば、オブジェクトではなくプリミティブ型です。
CIntは、C int型にマップされたSwift型です。
オブジェクトのメモリアドレスが必要な場合は、別のことを行う必要があります。
:スウィフトはCと対話するときに使用することができ、いくつかのポインタ型を持っており、あなたがここでそれらについて読むことができスウィフトポインタ型を
変換する方法を理解するために、(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でポインターを使用して実行できる1つのこと(これは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

はい、ポインタは存在する必要がありますが、参照した互換性の理由だけではありません。オペレーティングシステムによって通常使用されるポインタ。言語が高水準言語であっても、ポインタはオペレーティングシステムのエンジンでいつでも任意の言語で存在する必要があります。
holex 2014年

私は「互換性の理由とランタイムがそれを必要とするため」と述べました:-) 2番目のステートメントはあなたが言っていることを要約します(私はプログラマがそれを知って理解していると思いますので、私はいくつかの単語を費やしました)
LombaX

これはもう適用されないと思いますか?
aleclarson 2014

はい。@Drewからの正解を編集しました。
Rog

@LombaX参照タイプのアドレスのみを印刷できますか?変数のアドレスを出力できませんか?
AbhimanyuAryan 2015

21

オブジェクトの(ヒープ)アドレスを取得するには

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と同様に、に関連付けられた2つの異なるアドレスがありますo。1つ目はオブジェクトの場所、2つ目はオブジェクトへの参照(またはポインタ)の場所です。

はい、これは、デバッガーが通知できるように、アドレス0x7fff5fbfe658の内容が0x6100000011d0であることを意味します。

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

したがって、文字列が構造体であることを除いて、内部的にはこれはすべて(Objective-)Cとほとんど同じように機能します。

(Xcode 6.3現在)


うーん。オブジェクトのプロパティのスタックアドレスの取得に一貫性がありません。何か案は?この要点を確認してください!
aleclarson 2014

オブジェクトのプロパティはスタックではなくヒープ上にあります。クラスインスタンスのプロパティをUnsafePointerとして渡すと、Swiftが実際に値を最初にコピーし、コピーのアドレスを取得します。これは、Cコードがオブジェクトのインターフェースを迂回し、矛盾した状態を引き起こすのを防ぐためだと思います。それを回避する方法があるかどうかはわかりません。
nschum 14

これが私がApple Developer Forumsで作成したスレッドです。そこにいくつかの良い返信があります。
aleclarson 2014

20

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場所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()

メモリは2つの場所に割り当てられます。

  • クラスインスタンスデータが配置されているアドレス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

0x2a42(foo)で0x54あり、84(bar)です。

どちらの場合でも、&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つの異なるインスタンスを介して同じ構造体のアドレスを出力しようとすると、MemoryLocation2つの異なるアドレスが生成されることに注意してください。
user1046037

@ user1046037ありがとう、クラスinitに変更を加えました。また、2つの異なるアドレスを取得しますが、空の構造体を使用する場合のみです。空の構造体を使用すると、常に奇妙な結果が得られます。私の推測では、コンパイラーはいくつかの最適化を行います...
nyg

@ user1046037チェック:pastebin.com/mpd3ujw2。どうやら、すべての空の構造体は同じメモリアドレスを指しています。ただし、ポインターを変数に格納する場合は、ポインター(または構造体)のコピーが作成されます...
nyg

それは興味深いですが、2回印刷すると、異なるメモリアドレスが印刷されます。上記の回答も同様です。
user1046037

@ user1046037どういう意味かわかりませんが、コードはありますか?(常に同じメモリアドレスを取得します)
nyg

15

参照タイプ:

  • IDを表すため、参照型のメモリアドレスを取得することは理にかなっています。
  • === 識別演算子は、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

値のタイプ:

  • 値型のメモリアドレスを取得する必要性はそれほど重要ではなく(値であるため)、値の同等性に重点が置かれます。

12

これを使うだけです:

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

MyClass?」がCVarArgに準拠していないというコンパイラの不満を受け取った場合は、対応できますextension Optional : CVarArg { }。さもなければ、これは他の答えのすべての「安全でない」狂気なしに住所を印刷するようです。
Devin Lane

var _cVarArgEncoding: [Int]onの実装が必要CVarArgです。それがどのように実装されるべきか明確ではありません。
Yuchen Zhong

10

デバッガでこれを表示したいだけで、それ以外には何もしない場合は、実際にIntポインタを取得する必要はありません。メモリ内のオブジェクトのアドレスの文字列表現を取得するには、次のようなものを使用します。

public extension NSObject { // Extension syntax is cleaner for my use. If your needs stem outside NSObject, you may change the extension's 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...

1
ダウン投票には理由を説明するコメントを添えてください。私とここに来る他の誰もが、これがなぜ不十分な解決策であるかを知っています:)
Ben Leggiero

1
シンプルで清楚!
バダンガネーシュ

9

スウィフト5

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

この答えは間違っています。同じクラスの2つのインスタンスを作成すると、両方のインスタンスに同じメモリアドレスが返されます。 Unmanaged.passUnretained(myObject).toOpaque()代わりに正しく動作します。
Padraig 2018年

@Padraigありがとうございます。コードを更新しました。悲しいことに、今はAnyObjectパラメータを受け取ります。私はAny入力タイプとして好みます。
neoneye

6

Swift4でArrayについて:

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

1
私の日を救った。「最も有用な最近のそう獲得」のバッジがあるはずです
Anton Tropashko

実際、これが私のを印刷した唯一のアプローチですself?.array
Rostyslav Druzhchenko

4

他の答えは結構ですが、ポインタアドレスを整数として取得する方法を探していました。

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

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

ほんの少しフォローアップ。


スウィフト3.この回答のバージョンについては下記を参照してください
RenniePet

3

@Drewが提供する回答は、クラス型にのみ使用できます。
@nschumが提供する回答は、構造体型に対してのみ可能です。

ただし、2番目のメソッドを使用して、値型の要素を持つ配列のアドレスを取得する場合。Swiftでは配列がcopy-on-writeであり、SwiftがC / C ++に制御を渡すと(Swiftは&アドレスを取得するためにトリガーされる)、このように動作することを確認できないため、Swiftは配列全体をコピーします。そして、代わりに最初のメソッドを使用する場合、それは自動的に変換ArrayNSArrayれます。

したがって、私が見つけた最も単純で統一された方法は、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
}

3

これはSwift 3用です。

@CharlieMonroeのように、アドレスを整数として取得したかったのです。具体的には、スレッド名が使用できない状況で、診断ログモジュールのスレッドIDとして使用する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のようなアドレスを取得していなかったためです。最後のステートメントのモジュロ演算は、それを0x7DB3Fに変換します。


3

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>


2

これは確かにそれを回避するための最速または安全な方法ではありません。しかし、それは私にとってはうまくいきます。これにより、すべての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

フィードバックをありがとうジェフ、私は答えを更新します
チャールトンプロヴァタス

1
気にしないで!それは私の間違いでした!コードは、純粋なSwiftクラスで正常に動作します。間違いでごめんなさい。
ジェフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.