5 go
如果你看一下"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)
}
Run Code Online (Sandbox Code Playgroud)
你会看见:
_ = b[7] // early bounds check to guarantee safety of writes below
Run Code Online (Sandbox Code Playgroud)
现在考虑这个示例代码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)
}
Run Code Online (Sandbox Code Playgroud)
这个示例代码B(见注释):
package main
import "fmt"
func main() {
b := []byte{0, 1, 2, 3, 4, 5, 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)
}
Run Code Online (Sandbox Code Playgroud)
示例代码C:
package main
import "fmt"
func main() {
b := []byte{0, 1, 2, 3, 4, 5, 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)
}
Run Code Online (Sandbox Code Playgroud)
所以我有两个问题:
Q1:是否有必要进行早期检查以确保Golang中写入的安全性?
Q2:对于早期检查,保证写入的安全性,样本代码更简洁,性能更优化(速度),样本代码A,B,C或......?
A2:我觉得B:因为它简洁而且做早期检查,不是吗?
小智 2
\n\n\nQ1:Golang中是否需要提前进行边界检查来保证写入安全?
\n
这里的答案是“是和否”。一般来说,“不”,您通常不必在 Go 中插入边界检查,因为编译器会为您插入它们(这就是当您尝试访问超出切片长度的内存位置时您的示例会出现恐慌的原因)。但是,如果您要像给出的示例那样进行多次写入,那么“是”,您将需要像提供的示例那样插入早期边界检查,以确保您不会只有部分写入成功,使您处于糟糕的状态(或像示例 B 中所做的那样进行重构,以便第一次写入到最大的数组,确保在任何写入成功之前都会发生恐慌)。
\n\n然而,这并不是一个“go问题”,因为它是一类通用的错误。如果您不在任何语言中进行边界检查(或者如果它是像 Go 一样强制执行边界检查的语言,则不从最高索引开始),则写入不安全。这在很大程度上取决于具体情况;在您发布的标准库的示例中,用户边界检查是必要的。然而,在您发布的第二个示例中,用户边界检查不是必需的,因为代码可以像 B 一样编写,其中编译器在第一行插入边界检查。
\n\n\n\n\nQ2:为了进行早期边界检查以保证写入安全,哪个示例代码更简洁且性能优化(速度),示例代码 A、B、C 还是...?
\n\nA2:我认为 B:因为它很简洁并且进行了早期边界检查,不是吗?
\n
你是对的。在 B 中,编译器将在第一次写入时插入边界检查,以保护其余的写入。因为您使用常量(7
, 6
, \xe2\x80\xa6 0
)对切片进行索引,所以编译器可以从其余写入中省略边界检查,因为它可以保证它们是安全的。
归档时间: |
|
查看次数: |
427 次 |
最近记录: |