【发布时间】:2020-01-18 15:13:54
【问题描述】:
syscall 包已弃用。假设我有以下代码,我想将其迁移到未弃用的代码:
someGoObject := &struct{int; float32}{5, 45.4}
syscall.Syscall6(someProc.Addr(), 1, uintptr(unsafe.Pointer(someGoObject)), 0, 0, 0, 0, 0)
其中someProc 的类型为*syscall.LazyProc (Windows)。
sys subrepository(syscall 文档建议改用它)不再提供类似于syscall.Syscall 的功能,如果那里没有实现所需的功能,可以尝试通过以下方式解决问题方式,并相信工作已经完成:
someProc.Call(uintptr(unsafe.Pointer(someGoObject)))
现在someProc 的类型是*windows.LazyProc。
但是,如果我们这样做,我们将无法获得syscall.Syscall(和朋友)的保证之一,因为LazyProc.Call() is not implemented in assembly:
(4) 调用 syscall.Syscall 时将指针转换为 uintptr。
syscall 包中的 Syscall 函数传递它们的 uintptr 参数 直接到操作系统,然后可能,这取决于 调用的详细信息,将其中一些重新解释为指针。那是, 系统调用实现隐式转换某些 参数从 uintptr 返回到指针。
如果必须将指针参数转换为 uintptr 以用作 参数,该转换必须出现在调用表达式本身中:
syscall.Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(n))编译器处理转换为 uintptr 的指针 调用在汇编中实现的函数的参数列表 安排引用的已分配对象(如果有)被保留 并且在调用完成之前不会移动,即使来自类型 单独看来,在 打电话。
为了让编译器识别这种模式,转换必须出现 在参数列表中:
// INVALID: uintptr cannot be stored in variable // before implicit conversion back to Pointer during system call. u := uintptr(unsafe.Pointer(p)) syscall.Syscall(SYS_READ, uintptr(fd), u, uintptr(n))
(取自https://golang.org/pkg/unsafe/)
在我看来,唯一安全的方法是使用 C 分配内存。但是,这意味着我们需要复制数据并增加需要编写的代码量。
someObject := (*struct{int; float32})(C.calloc(1, unsafe.Sizeof(struct{int; float32}{}))) // Alloc
*someObject = struct{int; float32}{123, 456.789} // Fill with desired data
someProc.Call(uintptr(unsafe.Pointer(someObject))) // The actual call
C.free(unsafe.Pointer(someObject)) // Clean up
有没有更好的办法?
【问题讨论】:
标签: go