根据Golang导览,我们提供了以下整数类型:
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
Run Code Online (Sandbox Code Playgroud)
从理论上讲,这意味着我们还可以如下指向所有这些类型的指针:
*int *int8 *int16 *int32 *int64
*uint *uint8 *uint16 *uint32 *uint64 *uintptr
Run Code Online (Sandbox Code Playgroud)
如果是这种情况,那么我们已经有一个指向* uint形式的uint的指针。这会使uintptr变得多余。在官方文档不会在此洒下多少光:
uintptr is an integer type that is large enough to hold the bit pattern of any pointer.
Run Code Online (Sandbox Code Playgroud)
据我了解,这意味着uint的位宽是在编译时根据目标体系结构(通常为32位或64位)确定的。指针宽度也应缩放到目标体系结构似乎是合乎逻辑的(IE:32位* uint指向32位uint)。Golang就是这种情况吗?
另一个想法是,也许在添加uintptr时使语法在进行多个间接寻址时(IE:foo *uinptrvs foo **uint)不太混乱?
我最后的想法是,指针和整数在Golang中可能是不兼容的数据类型。这将非常令人沮丧,因为硬件本身在它们之间没有任何区别。例如,“分支到该地址”指令可以使用来自同一寄存器的与“添加此值”指令中相同的数据。
uintptr的真正意义(双关语)是什么?
简短的答案是“永不使用uintptr”。
长答案是uintptr在那里绕过类型系统,并允许Go实现者在Go中编写包括垃圾收集系统在内的Go运行时库,并使用未由 C指针处理的 C指针来调用C调用代码,包括系统调用。去吧
如果您充当实施者(例如,提供对新OS上的系统调用的访问权限),则需要uintptr。您还需要了解使用它所需的所有特殊技巧,例如,如果操作系统要对操作系统级别的线程进行堆栈操作,则将goroutine锁定到操作系统级别的线程。(如果将其与Go指针一起使用,则可能还需要告诉编译器不要移动goroutine堆栈,这是通过特殊的编译时指令完成的。)
编辑:正如kostix在注释中指出的那样,运行时系统将a unsafe.Pointer视为对对象的引用,从而使该对象对于GC保持活动状态。它不认为是uintptr这样的参考。(也就是说,虽然unsafe.Pointer具有指针类型,但uintptr具有整数类型。)另请参见package的文档unsafe。
uintptr 只是内存地址的整数表示形式,无论它指向的实际类型是什么。有点像void *C 语言,或者只是将指针转换为整数。它的目的是用于不安全的黑魔法,并且不会在日常的 go 代码中使用。