From 6ac2c3cbe694ea8ef21d65bf17a16b9aae59769c Mon Sep 17 00:00:00 2001 From: "Rick.Chan" Date: Wed, 11 Jan 2023 13:08:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86=E6=A0=BC=E5=BC=8F.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rick.Chan --- .../Language/Go/Basic/Pointer/Golang_的指针.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Software/Development/Language/Go/Basic/Pointer/Golang_的指针.md b/Software/Development/Language/Go/Basic/Pointer/Golang_的指针.md index 095d2aa..c2bd043 100644 --- a/Software/Development/Language/Go/Basic/Pointer/Golang_的指针.md +++ b/Software/Development/Language/Go/Basic/Pointer/Golang_的指针.md @@ -1,6 +1,12 @@ # Golang 的指针 -## unsafe.Pointer +- [Golang 的指针](#golang-的指针) + - [1. unsafe.Pointer](#1-unsafepointer) + - [2. unsafe.Sizeof、Alignof 和 Offsetof](#2-unsafesizeofalignof-和-offsetof) + - [3. 不要把 uintptr 类型赋值给临时变量](#3-不要把-uintptr-类型赋值给临时变量) + - [4. reflect 包返回的 uintptr](#4-reflect-包返回的-uintptr) + +## 1. unsafe.Pointer unsafe.Pointer 其实就是类似 C 的 void*,在 golang 中是用于各种指针相互转换的桥梁。uintptr 是 golang 的内置类型,是能存储指针的整型,uintptr 的底层类型是 int,它和 unsafe.Pointer 可相互转换。uintptr 和 unsafe.Pointer 的区别就是:unsafe.Pointer 只是单纯的通用指针类型,用于转换不同类型指针,它不可以参与指针运算;而 uintptr 是用于指针运算的,GC 不把 uintptr 当指针,也就是说 uintptr 无法持有对象,uintptr 类型的目标会被回收。golang 的 unsafe 包很强大,基本上很少会去用它。它可以像 C 一样去操作内存,但由于 golang 不支持直接进行指针运算,所以用起来稍显麻烦。 @@ -51,7 +57,7 @@ func main() { 核心思想就是:结构体的成员在内存中的分配是一段连续的内存,结构体中第一个成员的地址就是这个结构体的地址,您也可以认为是相对于这个结构体偏移了 0。相同的,这个结构体中的任一成员都可以相对于这个结构体的偏移来计算出它在内存中的绝对地址。 -## unsafe.Sizeof、Alignof 和 Offsetof +## 2. unsafe.Sizeof、Alignof 和 Offsetof 函数 unsafe.Sizeof 报告传递给它的参数在内存中占用的字节(Byte)长度(1Byte=8bit,1个字节是8位),参数可以是任意类型的表达式,但它不会对表达式进行求值。对 Sizeof 的调用会返回一个 uintptr 类型的常量表达式,所以返回的结果可以作为数组类型的长度大小,或者用作计算其他的常量: @@ -85,7 +91,7 @@ func main() { 虽然这几个函数在不安全的unsafe包里,但是这几个函数是安全的,特别在需要优化内存空间时它们返回的结果对于理解原生的内存布局很有帮助。 -## 不要把 uintptr 类型赋值给临时变量 +## 3. 不要把 uintptr 类型赋值给临时变量 下面这段代码看似和上面的一样的,引入了一个临时变量 tmp,让把原来的一行拆成了两行,这里的 tmp 是 uintptr 类型。这种引入 uintptr 类型的临时变量,破坏原来整行代码的用法是错误的: @@ -118,7 +124,7 @@ possible misuse of unsafe.Pointer 所以还是可以在编译的时候发现的。这里强烈建议遵守最小可用原则,不要使用任何包含变量地址的 uintptr 类型的变量,并减少不必要的 unsafe.Pointer 类型到 uintptr 类型的转换。像本小节第一个例子里那样,转换为 uintptr 类型,最终在转换回 unsafe.Pointer 类型的操作,都要在一条语句中完成。 -## reflect 包返回的 uintptr +## 4. reflect 包返回的 uintptr 调用一个库函数,并且返回的是 uintptr 类型地址时,比如下面的 reflect 包中的几个函数。这些结果应该立刻转换为 unsafe.Pointer 来确保它们在接下来代码中能够始终指向原来的变量: