Skip to content

Commit

Permalink
Merge pull request hantmac#137 from luobangkui/2.3.3-2.3.5
Browse files Browse the repository at this point in the history
完成2.3.3-2.3.5章节
  • Loading branch information
hantmac committed Jul 29, 2019
2 parents 01b612b + 072762d commit b6971ea
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
- [02.3 垃圾回收](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.3.md)
- [02.3.1 三色算法](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.3.1.md)
- [02.3.2 垃圾回收器背后的更多操作](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.3.2.md)
- [02.3.3 Unsafe code](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.3.3.md)
- [02.3.4 关于unsafe包](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.3.4.md)
- [02.3.5 另一个usafe包的例子](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.3.5.md)
- [02.5 C中调用Go函数](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.5.md)
- [02.5.1 Go Package](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.5.1.md)
- [02.5.2 C代码](https://github.com/hantmac/Mastering_Go_ZH_CN/blob/master/eBook/chapter2/02.5.2.md)
Expand Down Expand Up @@ -332,6 +335,7 @@
- [themoonbear](https://github.com/themoonbear)
- [klew](https://github.com/kasheemlew)
- [foxxnuaa](https://github.com/foxxnuaa)
- [luobangkui](https://github.com/luobangkui)

---------
### 授权许可
Expand Down
58 changes: 58 additions & 0 deletions eBook/chapter2/02.3.3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
### Unsafe code

**Unsafe code**是一种绕过go类型安全和内存安全检查的Go代码。大多数情况,unsafe code是和指针相关的。但是要记住使用unsafe code有可能会损害你的程序,所以,如果你不完全确定是否需要用到unsafe code就不要使用它。

以下面的```unsafe.go```为例,看一下unsafe code的使用

```
package main
import (
"fmt"
"unsafe"
)
func main() {
var value int64 = 5
var p1 = &value
var p2 = (*int32)(unsafe.Pointer(p1))
```
这里使用了```unsafe.Pointer()```方法,这个方法能让你创造一个```int32``````p2```指针去指向一个```int64``````value```变量,而这个变量是使用```p1```指针去访问的,注意这种做法是有风险的。

任何go指针都可以转化为```unsafe.Pointer```指针。

###### *```unsafe.Pointer```类型的指针可以覆盖掉go的系统类型。这毫无疑问很快,但是如果不小心或者不正确使用的话就会很危险,它给了开发者更多选择去掌控数据。*

```unsafe.go```后面部分如下

```
fmt.Println("*p1: ", *p1)
fmt.Println("*p2: ", *p2)
*p1 = 5434123412312431212
fmt.Println(value)
fmt.Println("*p2: ", *p2)
*p1 = 54341234
fmt.Println(value)
fmt.Println("*p2: ", *p2)
}
```
###### *你可以使用一个星号(***)来解引用一个指针*

运行```unsafe.go```,会得到如下的输出

```
*p1: 5
*p2: 5
5434123412312431212
*p2: -930866580
54341234
*p2: 54341234
```

那么这个输出说明了什么呢?它告诉了我们,使用32-bit的指针无法存一个64-bit的整数型

下一节你会看到,使用```unsafe```库中的方法可以做许多有趣的事情




23 changes: 23 additions & 0 deletions eBook/chapter2/02.3.4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
### 关于unsafe包

你已经实际操作过```unsafe```包的东西了,现在来看一下为什么这个库这么特别。



首先,如果你看了```unsafe```包的源码,你可能会感到惊讶。在macOS Hight Sierra系统上,可以使用**Homebrew**安装1.9.1版本的Go 。```unsafe```源码路径在```/usr/local/Cellar/go/1.9.1/libexec/src/unsafe/unsafe.go```下面,不包含注释,它的内容如下

```
$ cd /usr/local/Cellar/go/1.9.1/libexec/src/unsafe/
$ grep -v '^//' unsafe.go|grep -v '^$'
package unsafe
type ArbitraryType int
type Pointer *ArbitraryType
func Sizeof(x ArbitraryType) uintptr
func Offsetof(x ArbitraryType) uintptr
func Alignof(x ArbitraryType) uintptr
```

OK,其它的```unsafe```包的go代码去哪里了?答案很简单:当你import到你程序里的时候,Go编译器实现了这个unsafe库。

###### *许多系统库,例如```runtime```,```syscall``````os```会经常使用到```usafe```*
53 changes: 53 additions & 0 deletions eBook/chapter2/02.3.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
### 另一个usafe包的例子

在这一节,你会了解到更多关于```unsafe```库的东西,以及通过一个```moreUnsafe.go```的小程序来了解unsafe库的兼容性。```moreUnsafe.go```做的事情就是使用指针来访问数组里的所有元素。


```
package main
import (
"fmt"
"unsafe"
)
func main() {
array := [...]int{0, 1, -2, 3, 4}
pointer := &array[0]
fmt.Print(*pointer, " ")
memoryAddress := uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0])
for i := 0; i < len(array)-1; i++ {
pointer = (*int)(unsafe.Pointer(memoryAddress))
fmt.Print(*pointer, " ")
memoryAddress = uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0])
}
```

首先,```pointer```变量指向```array[0]```的地址,```array[0]```是整型数组的第一个元素。接下来指向整数值的```pointer```变量会传入```unsafe.Pointer()```方法,然后传入```uintptr```。最后结果存到了```memoryAddress```里。


```unsafe.Sizeof(array[0])```是为了去访问下一个数组元素,这个值是每个元素占的内存大小。每次for循环遍历,都会把这个值加到```memoryAddress```上,这样就能获取到下一个数组元素的地址。```*pointer```*符号对指针进行解引用,然后返回了所存的整数值。


后面部分代码如下:


```
fmt.Println()
pointer = (*int)(unsafe.Pointer(memoryAddress))
fmt.Print("One more: ", *pointer, " ")
memoryAddress = uintptr(unsafe.Pointer(pointer)) + unsafe.Sizeof(array[0])
fmt.Println()
}
```

这里,我们尝试使用指针和内存地址去访问一个不存在的数组元素。由于使用```unsafe```包,Go编译器不会捕捉到这样的逻辑错误,因而会产生一些不可预料的事情。

执行```moreUnsafe.go```,会产生如下的输出:

```
$ go run moreUnsafe.go
0 1 -2 3 4
One more: 824634191624
```
现在,你使用指针访问了Go数组里的所有元素。但是,这里真正的问题是,当你尝试访问无效的数组元素,程序并不会出错而是会返回一个随机的数字。

0 comments on commit b6971ea

Please sign in to comment.