1 回答
TA贡献1863条经验 获得超2个赞
那个设定
所以,基本上,你得到的映射是
int* buffer→buffer uintptrint argc→unsafe.Pointer(&argsCount),其中&argsCount是一个指向intchar* argv[]→unsafe.Pointer(&args),哪里args是[]stringconst char* fileName→unsafe.Pointer(syscall.StringToUTF16Ptr(fileName))const char* key,const char* prefix,const char* version— 同上。
存在的问题
现在这有什么问题呢。
uintptr禁止在函数之间传递包含活动 Go 对象地址的值。(稍后会详细介绍。)argsCount您将函数参数的地址传递给argc。如果将其解释为计数,则典型的商品平台/操作系统(例如 amd64/Windows)上的地址是一个极其巨大的值。我敢打赌,当函数尝试从中读取这么多元素时,它会崩溃,导致
argv它读取进程未映射的内存。这里有两个问题:
将切片值的地址作为参数传递,期望该切片的第一个元素的地址是错误的。
这是因为切片值(目前,在您应该使用的“参考”Go 实现中)是具有
struct3 个字段的:底层数据数组的地址、该数组中允许使用的元素数以及总数该数组中此类元素的计数append,在对切片值调用时,函数可以使用这些元素,而无需重新分配。当您拥有
args []string并执行时&args,您将获得该结构的地址,而不是该切片的第一个元素的地址。要执行后者,请使用
&args[0].在 Go 中,字符串(通常是这样,我们假设是这样)包含编码为 UTF-8 的字符。这通常不是 Windows 本机 C++ 代码在表示需要
char *.我猜,你需要首先为 构建一个合适的东西
argv,比如argv := make([]unsafe.Pointer, 0, len(args))for i, s := range args { argv[i] = unsafe.Pointer(syscall.StringToUTF16Ptr(s)) }然后传递
&argv[0]给被调用者。但请参阅下文
syscall.StringToUTF16Ptr()。
您正在做的将字符串数据传递给具有该类型的其余参数的准备工作
const char*似乎是正确的,但前提是被调用者确实意味着它char是一个 16 位整数。换句话说,用于编译该库的源代码和工具链必须确保它
char确实是wchar_t或WCHAR。如果是,那么你的做法应该没问题;否则就不是。你应该验证这一点。
uintptr关于在表达式之间传递 s 的注意事项
Go 具有垃圾收集功能,因此它的运行时必须知道指向所有当前活动对象的所有指针。只要存在一个变量,其中包含指向在程序运行时分配的内存块的指针,该块就不会被垃圾收集。
值unsafe.Pointer算作对内存块的正确引用,但uintptr值则不然。这意味着当代码
p := new(someType) u := uintptr(unsafe.Pointer(&p)) foo(u)return
p正在运行时,一旦分配了地址,GC 就可以自由地回收由 分配的对象p,因为p是对该对象的唯一引用,但u事实并非如此。
现在考虑参考 Go 实现中的 GC 与程序代码同时运行。这意味着当foo运行时,GC 也可能会执行,并且它可能会将您的实例someType从foo.
作为此一般规则的一个例外,Go 编译器保证uintptr(unsafe.Pointer)同一语言表达式中发生的所有类型转换都不受 GC 的影响。所以以我们之前的例子为例,这样做就可以了
foo(uintptr(unsafe.Pointer(new(someType)))return
和
p := new(someType) v := unsafe.Pointer(&p) foo(uintptr(v))return
因为类型转换发生uintptr在单个表达式中——这是一个函数调用。
因此,您不能将指向 Go 对象的指针作为uintptrs传递,除非它们包含从“C 端”获取的指针。
- 1 回答
- 0 关注
- 223 浏览
添加回答
举报
