go语言圣经第十三章(读书笔记)

第十三章 底层编程

  • 本章提供的方法不应该轻易使用(译注:属于黑魔法,虽然可能功能很强大,但是也容易误伤到自己)。如果没有处理好细节,它们可能导致各种不可预测的并且隐晦的错误,甚至连有经验的的C语言程序员也无法理解这些错误。使用unsafe包的同时也放弃了Go语言保证与未来版本的兼容性的承诺,因为它必然会在有意无意中会使用很多实现的细节,而这些实现的细节在未来的Go语言中很可能会被改变。

unsafe.Sizeof, Alignof和Offsetof

  • unsafe.Sizeof函数返回操作数在内存中的字节大小,参数可以是任意类型的表达式,但是它并不会对表达式进行求值
import "unsafe"
fmt.Println(unsafe.Sizeof(float64(0))) // "8"
  • 内存对齐问题:
    1.计算机在加载和保存数据时,如果内存地址合理地对齐,将会更有效率
    2.例如2字节大小的int16类型的变量地址应该是偶数,一个4字节大小的rune类型变量地址应该是4的倍数,一个8字节大小的float64类型变量地址应该是8字节对齐的
    3.对于再大的地址对齐倍数则是不需要的,像complex128,最多也只是8字节对齐

  • 由于内存对齐的存在,对于一个聚合类型(结构体或者数组)的大小至少是所有字段或者元素大小的总和,或者更大从而产生内存空洞

  • 对于结构体来说,声明字段的顺序不同,会导致其占用内存大小的不同
                               // 64-bit 32-bit
struct{ bool; float64; int16 } // 3 words 4words
struct{ float64; int16; bool } // 2 words 3words
struct{ bool; int16; float64 } // 2 words 3words

  • unsafe.Alignof函数返回对应参数的类型需要对齐的倍数
  • unsafe.Offsetof函数的参数必须是一个字段x.f, 然后返回f字段相对于x起始地址的偏移量, 包括可能的空洞.

//32位系统
Sizeof(x) = 16
Alignof(x) = 4
Sizeof(x.a) = 1 Alignof(x.a) = 1 Offsetof(x.a) = 0
Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2
Sizeof(x.c) = 12 Alignof(x.c) = 4 Offsetof(x.c) = 4

//64位系统
Sizeof(x) = 32
Alignof(x) = 8
Sizeof(x.a) = 1 Alignof(x.a) = 1 Offsetof(x.a) = 0
Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2
Sizeof(x.c) = 24 Alignof(x.c) = 8 Offsetof(x.c) = 8

unsafe.Pointer

  • unsafe.Pointer类似C语言中的void* 类型指针,
    1.可以包含任意类型变量的地址,但是却不能用p来获取其真实变量的值,因为我们并不知道变量的具体类型
    2.可以和nil进行比较
    3.可以和普通的*T互相转化,并且转化为普通指针时,不需要和原始的
    T类型相同
package math
func Float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) }
fmt.Printf("%#016x\n", Float64bits(1.0)) // "0x3ff0000000000000"

通过cgo调用c代码

  • 这一小节实操性强,看回原书
  • 几个关键点:
    1.import "C"
    2.c语言写的源文件
posted @ 2019-07-27 14:08  DickLai  阅读(130)  评论(0)    收藏  举报