整理格式.

Signed-off-by: Rick.Chan <cy@haoan119.com>
This commit is contained in:
Rick.Chan 2023-01-11 13:08:23 +08:00
parent c708fe75a4
commit 6ac2c3cbe6
1 changed files with 10 additions and 4 deletions

View File

@ -1,6 +1,12 @@
# Golang 的指针 # 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 不支持直接进行指针运算,所以用起来稍显麻烦。 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。相同的这个结构体中的任一成员都可以相对于这个结构体的偏移来计算出它在内存中的绝对地址。 核心思想就是:结构体的成员在内存中的分配是一段连续的内存,结构体中第一个成员的地址就是这个结构体的地址,您也可以认为是相对于这个结构体偏移了 0。相同的这个结构体中的任一成员都可以相对于这个结构体的偏移来计算出它在内存中的绝对地址。
## unsafe.Sizeof、Alignof 和 Offsetof ## 2. unsafe.Sizeof、Alignof 和 Offsetof
函数 unsafe.Sizeof 报告传递给它的参数在内存中占用的字节Byte长度1Byte=8bit1个字节是8位参数可以是任意类型的表达式但它不会对表达式进行求值。对 Sizeof 的调用会返回一个 uintptr 类型的常量表达式,所以返回的结果可以作为数组类型的长度大小,或者用作计算其他的常量: 函数 unsafe.Sizeof 报告传递给它的参数在内存中占用的字节Byte长度1Byte=8bit1个字节是8位参数可以是任意类型的表达式但它不会对表达式进行求值。对 Sizeof 的调用会返回一个 uintptr 类型的常量表达式,所以返回的结果可以作为数组类型的长度大小,或者用作计算其他的常量:
@ -85,7 +91,7 @@ func main() {
虽然这几个函数在不安全的unsafe包里但是这几个函数是安全的特别在需要优化内存空间时它们返回的结果对于理解原生的内存布局很有帮助。 虽然这几个函数在不安全的unsafe包里但是这几个函数是安全的特别在需要优化内存空间时它们返回的结果对于理解原生的内存布局很有帮助。
## 不要把 uintptr 类型赋值给临时变量 ## 3. 不要把 uintptr 类型赋值给临时变量
下面这段代码看似和上面的一样的,引入了一个临时变量 tmp让把原来的一行拆成了两行这里的 tmp 是 uintptr 类型。这种引入 uintptr 类型的临时变量,破坏原来整行代码的用法是错误的: 下面这段代码看似和上面的一样的,引入了一个临时变量 tmp让把原来的一行拆成了两行这里的 tmp 是 uintptr 类型。这种引入 uintptr 类型的临时变量,破坏原来整行代码的用法是错误的:
@ -118,7 +124,7 @@ possible misuse of unsafe.Pointer
所以还是可以在编译的时候发现的。这里强烈建议遵守最小可用原则,不要使用任何包含变量地址的 uintptr 类型的变量,并减少不必要的 unsafe.Pointer 类型到 uintptr 类型的转换。像本小节第一个例子里那样,转换为 uintptr 类型,最终在转换回 unsafe.Pointer 类型的操作,都要在一条语句中完成。 所以还是可以在编译的时候发现的。这里强烈建议遵守最小可用原则,不要使用任何包含变量地址的 uintptr 类型的变量,并减少不必要的 unsafe.Pointer 类型到 uintptr 类型的转换。像本小节第一个例子里那样,转换为 uintptr 类型,最终在转换回 unsafe.Pointer 类型的操作,都要在一条语句中完成。
## reflect 包返回的 uintptr ## 4. reflect 包返回的 uintptr
调用一个库函数,并且返回的是 uintptr 类型地址时,比如下面的 reflect 包中的几个函数。这些结果应该立刻转换为 unsafe.Pointer 来确保它们在接下来代码中能够始终指向原来的变量: 调用一个库函数,并且返回的是 uintptr 类型地址时,比如下面的 reflect 包中的几个函数。这些结果应该立刻转换为 unsafe.Pointer 来确保它们在接下来代码中能够始终指向原来的变量: