是否有必要进行早期检查以确保Golang中写入的安全性?
如果你看一下“encoding / binary”包:
func (littleEndian) Uint64(b []byte) uint64 { _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 } func (littleEndian) PutUint64(b []byte,v uint64) { _ = b[7] // early bounds check to guarantee safety of writes below b[0] = byte(v) b[1] = byte(v >> 8) b[2] = byte(v >> 16) b[3] = byte(v >> 24) b[4] = byte(v >> 32) b[5] = byte(v >> 40) b[6] = byte(v >> 48) b[7] = byte(v >> 56) } 你会看见: _ = b[7] // early bounds check to guarantee safety of writes below 现在考虑这个示例代码A(请参阅注释): package main import "fmt" func main() { b := []byte{0,1,2,3,4,5,6} var v uint64 = 0x0807060504030201 b[0] = byte(v) b[1] = byte(v >> 8) b[2] = byte(v >> 16) b[3] = byte(v >> 24) b[4] = byte(v >> 32) b[5] = byte(v >> 40) b[6] = byte(v >> 48) b[7] = byte(v >> 56) // panic: runtime error: index out of range fmt.Println(b) } 这个示例代码B(见注释): package main import "fmt" func main() { b := []byte{0,6} var v uint64 = 0x0807060504030201 b[7] = byte(v >> 56) // panic: runtime error: index out of range b[6] = byte(v >> 48) b[5] = byte(v >> 40) b[4] = byte(v >> 32) b[3] = byte(v >> 24) b[2] = byte(v >> 16) b[1] = byte(v >> 8) b[0] = byte(v) fmt.Println(b) } 示例代码C: package main import "fmt" func main() { b := []byte{0,6} var v uint64 = 0x0807060504030201 _ = b[7] // early bounds check to guarantee safety of writes below b[0] = byte(v) b[1] = byte(v >> 8) b[2] = byte(v >> 16) b[3] = byte(v >> 24) b[4] = byte(v >> 32) b[5] = byte(v >> 40) b[6] = byte(v >> 48) b[7] = byte(v >> 56) fmt.Println(b) } 所以我有两个问题: A2:我觉得B:因为它简洁而且做早期检查,不是吗?
这里的答案是“是和否”.通常,“不”,您通常不必在Go中插入边界检查,因为编译器会为您插入它们(这就是为什么当您尝试访问超出切片长度的内存位置时,示例会出现紧急情况).但是,如果您正在执行多次写入,例如给出的示例,“是”,则需要插入早期边界检查,例如提供的示例,以确保您没有只有部分写入成功,处于错误状态(或者像在示例B中那样重构,以便第一次写入到最大的数组,确保在任何写入成功之前发生恐慌). 然而,这不是一个“问题”,因为它是一个通用的bug类.如果您不以任何语言进行边界检查(或者不以最高索引开始,如果它是一种强制执行边界检查自己的语言,如Go),则写入不安全.它也在很大程度上取决于情况;在您发布的标准库的示例中,必须进行用户边界检查.但是,在您发布的第二个示例中,不需要进行用户边界检查,因为代码可以像B一样编写,其中编译器在第一行插入边界检查.
你是对的.在B中,编译器将在第一次写入时插入边界检查,以保护其余写入.因为您使用常量(7,6,… 0)索引切片,所以编译器可以从其余写入中删除边界检查,因为它可以保证它们是安全的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |