[swift] 신속한 메모리 주소 인쇄

어쨌든 [NSString stringWithFormat:@"%p", myVar]Objective-C에서 새로운 Swift 언어로 를 시뮬레이션 할 수 있습니까?

예를 들면 다음과 같습니다.

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



답변

스위프트 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

스위프트 3의 경우 다음을 사용하십시오 withUnsafePointer.

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


답변

참고 : 이것은 참조 유형입니다.

스위프트 4/5 :

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

someVar의 메모리 주소를 인쇄합니다. (@Ying 덕분에)


스위프트 3.1 :

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

someVar의 메모리 주소를 인쇄합니다.



답변

이 답변은 상당히 오래되었습니다. 설명하는 많은 방법이 더 이상 작동하지 않습니다. 특히 .core더 이상 액세스 할 수 없습니다.

그러나 @drew의 대답은 정확하고 간단합니다.

이제는 표준 라이브러리 인 unsafeAddressOf의 일부입니다.

따라서 귀하의 질문에 대한 답변은 다음과 같습니다.

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

다음은 정답으로 표시된 원래 답변입니다 (후손 / 정치).

스위프트는 “숨김”포인터를 가리지 만 여전히 후드 아래에 존재합니다. (런타임이 필요하기 때문에 Objc 및 C와의 호환성 이유로)

그러나 알아야 할 것이 없지만 먼저 Swift String의 메모리 주소를 인쇄하는 방법은 무엇입니까?

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

이것은 문자열의 메모리 주소를 인쇄합니다. XCode-> 디버그 워크 플로-> 메모리보기를 열고 인쇄 된 주소로 이동하면 문자열의 원시 데이터가 표시됩니다. 이것은 문자열 리터럴이므로 이진 저장소 (스택 또는 힙이 아님) 내의 메모리 주소입니다.

그러나 당신이 할 경우

    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 유형입니다.
객체의 메모리 주소를 원한다면 다른 것을해야합니다.
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
*/

( 요점 )


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

메모리는 두 곳에 할당됩니다 :

  • 클래스 인스턴스 데이터가있는 주소 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)이고 0x5484 (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).

나는 이것이 도움이 되었기를 바란다.


답변

참조 유형 :

  • ID를 나타내는 참조 유형의 메모리 주소를 얻는 것이 좋습니다.
  • === identity 연산자는 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

가치 유형 :

  • 값 유형의 메모리 주소를 가져와야하는 것은 그다지 중요하지 않으며 (값이므로) 값의 동등성에 더 중점을 둡니다.

답변

이것을 사용하십시오 :

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