如何获取UnsafeMutableRawPointer的值?

3

我试图获取UnsafeMutableRawPointer所指向的地址,但是我无法做到。由于我对Swift还很陌生,可能存在遗漏或者完全错误的地方。最好的情况是将原始值强制转换为CChar。

输入图片说明


你从哪里获取这个指针,并且你想在哪里使用它? - Alexander
@AlexanderMomchliov 我在尝试连接汇编和Swift。努力理解不安全类型的机制。 - jack sexton
“获取由UnsafeMutableRawPointer指向的地址”是什么意思?您想将“0x0...0404340”作为存储在“Int”或其他某个变量中的值吗? - Alexander
你想用这个 Int 做什么,而你不能用 UnsafeMutableRawPointer 更安全、更表达的方式来完成吗? - Alexander
@AlexanderMomchliov 我将调用一个汇编写的例程,我需要按照sys v abi传递参数给例程。其中一个参数是void*,因此我需要UnsafeMutableRawPointer的实际值。 - jack sexton
显示剩余2条评论
2个回答

4

提醒路人:我的答案很多地方可能不太合理,因为它并没有回答上面的初始问题,而是回答了与OP的聊天中出现的问题。

花了我几个小时的时间,但现在我学会了一些汇编语言,可以回答一些问题。

  1. CChar是一个C Char,字面意思就是表示Cchar类型。它是Int8typealias。它是一个单独的字节。你不能像指针类型那样使用它,因为这些指针在64位机器上有8个字节。

  2. 你不需要所有这些UnsafeMutableRawPointer的样板代码,你当然也不需要访问它的原始值。你可以直接传递数组到期望指针的位置。

    当一个函数被声明为接受一个UnsafePointer参数时,它可以接受以下任何一种:

    • A [Type] value, which is passed as a pointer to the start of the array.

    来自与C API交互 - 指针

  3. 你遇到的问题是,你对0x8(%rdi)的改变似乎没有在Swift端反映出来。这里的问题是,你正在写入8个字节的偏移量,但是print(a.load(as: void_star.self))正在读取第一个字节。你正在读取一个你从未修改过的字节。

我进行了进一步的探索。这是我的冒险战利品:

exampleSwift.swift:

@_silgen_name("incrementByValue")
    func incrementByValue(_: Int64)

@_silgen_name("incrementByReference")
    func incrementByReference(_: inout Int64)

@_silgen_name("return1234")
    func return1234() -> Int64

@_silgen_name("incrementElements")
    func incrementElements(of _: UnsafeRawPointer, count _: Int)

var a: Int64 = 100
print("\"a\" before \"incrementByValue(a)\": \(a)")
incrementByValue(a)
print("\"a\" after \"incrementByValue(a)\": \(a)\n")

var b: Int64 = 200
print("\"b\" before \"incrementByValue(b)\": \(b)")
incrementByReference(&b)
print("\"b\" after \"incrementByValue(b)\": \(b)\n")

print("return1234() returned: \(return1234())\n")

var array: [Int64] = Array(0...5)

print("\"array\" before incrementElements(of: array, count: array.count): \n\t\(array)")
incrementElements(of: array, count: array.count)
print("\"array\" after incrementElements(of: array, count: array.count): \n\t\(array)\n")

exampleASM.s:

.text

.globl _incrementByValue
.globl _incrementByReference
.globl _return1234
.globl _incrementElements

// A test routine that demonstrates operating on a value
_incrementByValue:
    // %rdi contains a copy of the argument passed in.
    // Changes here won't be reflected back in Swift
    incq %rdi
    ret

// A test routine that demonstrates operating on a reference
_incrementByReference:
    // %rdi contains a reference tp the argument passed in.
    // Changes to the reference itself won't be reflected back in Swift,
    // but changes to the referenced memory will.
    incq (%rdi)
    ret

// A test routine that demonstrates the use of %rax for returning a value
_return1234:
    movq $1234, %rax    // return value is in rax
    ret

//A test routine that demonstrates operating on an array
_incrementElements:
    // %rdi: Pointer to first of n Int64 elements
    // %rsi: the array count, n

    movq    %rsi, %rcx  // Set loop counter (%rcx) to n
    aLoop:
        incq    (%rdi)      // increment value pointer to by %rdi
        add     $8, %rdi    // advance pointer by 8 bytes
        loop    aLoop       // loop back to aLoop if rcx > 0

    ret

使用以下命令进行编译、链接和运行:

llvm-g++ -c exampleASM.s &&
swiftc -c exampleSwift.swift &&
ld exampleASM.o exampleSwift.o -o exampleBinary -force_load /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_macosx.a -framework CoreFoundation -macosx_version_min 10.12.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -lobjc -lSystem -arch x86_64 -L /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -rpath /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -no_objc_category_merging &&
./exampleBinary

输出:

"a" before "incrementByValue(a)": 100
"a" after "incrementByValue(a)": 100

"b" before "incrementByValue(b)": 200
"b" after "incrementByValue(b)": 201

return1234() returned: 1234

"array" before incrementElements(of: array, count: array.count): 
    [0, 1, 2, 3, 4, 5]
"array" after incrementElements(of: array, count: array.count): 
    [1, 2, 3, 4, 5, 6]

非常感谢你的努力,真的很感激。 - jack sexton
@jacksexton 请记住,在Swift达到ABI稳定之前,所有这些都不是铁板钉钉的。在此之前,可能会有变化,并且很有可能发生变化。 - Alexander
我正在学习Swift中的堆栈/堆,并遇到了这个问题。老实说,我不知道你们在谈论什么,但我真的很佩服@Alexander,从你与OP讨论帮助开始,尽管一开始你并不知道太多关于它的事情...感谢你花费时间! - nahung89
@nahung89 请查看此聊天室以获取上下文。 - Alexander

3

将MutableRawPointer转换为对象,我们使用fromOpaque API。

/// Unsafely turns an opaque C pointer into an unmanaged class reference.
///
/// This operation does not change reference counts.
///
///     let str: CFString = Unmanaged.fromOpaque(ptr).takeUnretainedValue()
///
/// - Parameter value: An opaque C pointer.
/// - Returns: An unmanaged class reference to `value`.
public static func fromOpaque(_ value: UnsafeRawPointer) -> Unmanaged<Instance>

例子:

var info:UnsafeMutableRawPointer = ....
let obj = Unmanaged<$AnyObject>.fromOpaque(info).takeUnretainedValue()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接