为什么在 unsafe.Sizeof() 中取消引用 nil 指针不会导致恐慌?
Why doesn't dereferencing a nil pointer in unsafe.Sizeof() cause a panic?
https://go.dev/play/p/X_BH4qGgXHJ
package main
import (
"fmt"
"unsafe"
)
func main() {
var i *int
fmt.Println(unsafe.Sizeof(*i)) // dereference of null pointer i
}
为什么这段代码没有
unsafe.Sizeof(*i)
导致运行时恐慌?
Calls to Alignof
, Offsetof
, and Sizeof
are compile-time constant expressions of type uintptr
.
这些函数在编译时求值,在运行时不会发生实际的解除引用。
这是可能的,因为不需要指向的值,只需要有关其类型的信息,不需要取消引用。
它也记录在 unsafe.Sizeof()
:
The return value of Sizeof is a Go constant.
Go 中的常量是 compile-time 个常量。
A constant value is represented by a rune, integer, floating-point, imaginary, or string literal, an identifier denoting a constant, a constant expression, a conversion with a result that is a constant, or the result value of some built-in functions such as unsafe.Sizeof
applied to any value, cap
or len
applied to some expressions, real
and imag
applied to a complex constant and complex applied to numeric constants.
查看类似的示例(如果不将它们传递给 unsafe.Sizeof()
会在运行时恐慌或无限期阻塞,但它们工作得很好):
fmt.Println(unsafe.Sizeof(*(*int8)(nil))) // 1, no dereferencing
fmt.Println(unsafe.Sizeof([]int16{}[10])) // 2, no indexing
x := "hi"
fmt.Println(unsafe.Sizeof(x[10])) // 1, no indexing
fmt.Println(unsafe.Sizeof(map[interface{}]int{}[[]int{}])) // 8, no indexing
fmt.Println(unsafe.Sizeof((interface{})(nil).(int16))) // 2, no type assertion
i := 0
fmt.Println(unsafe.Sizeof(i / i)) // 8, no division by 0
i = -1
fmt.Println(unsafe.Sizeof(1 << i)) // 8, no negative shift count
fmt.Println(unsafe.Sizeof(make([]int, i))) // 24, no negative length
fmt.Println(unsafe.Sizeof((*[1]int)([]int{}))) // 8, no converting to bigger array
fmt.Println(unsafe.Sizeof((func() int32)(nil)())) // 4, no function call
fmt.Println(unsafe.Sizeof(<-(chan int64)(nil))) // 8, no receiving
var a, b interface{} = []int{}, []int{}
fmt.Println(unsafe.Sizeof(a == b)) // 1, no comparison
在 Go Playground 上试试这些。
https://go.dev/play/p/X_BH4qGgXHJ
package main
import (
"fmt"
"unsafe"
)
func main() {
var i *int
fmt.Println(unsafe.Sizeof(*i)) // dereference of null pointer i
}
为什么这段代码没有
unsafe.Sizeof(*i)
导致运行时恐慌?
Calls to
Alignof
,Offsetof
, andSizeof
are compile-time constant expressions of typeuintptr
.
这些函数在编译时求值,在运行时不会发生实际的解除引用。
这是可能的,因为不需要指向的值,只需要有关其类型的信息,不需要取消引用。
它也记录在 unsafe.Sizeof()
:
The return value of Sizeof is a Go constant.
Go 中的常量是 compile-time 个常量。
A constant value is represented by a rune, integer, floating-point, imaginary, or string literal, an identifier denoting a constant, a constant expression, a conversion with a result that is a constant, or the result value of some built-in functions such as
unsafe.Sizeof
applied to any value,cap
orlen
applied to some expressions,real
andimag
applied to a complex constant and complex applied to numeric constants.
查看类似的示例(如果不将它们传递给 unsafe.Sizeof()
会在运行时恐慌或无限期阻塞,但它们工作得很好):
fmt.Println(unsafe.Sizeof(*(*int8)(nil))) // 1, no dereferencing
fmt.Println(unsafe.Sizeof([]int16{}[10])) // 2, no indexing
x := "hi"
fmt.Println(unsafe.Sizeof(x[10])) // 1, no indexing
fmt.Println(unsafe.Sizeof(map[interface{}]int{}[[]int{}])) // 8, no indexing
fmt.Println(unsafe.Sizeof((interface{})(nil).(int16))) // 2, no type assertion
i := 0
fmt.Println(unsafe.Sizeof(i / i)) // 8, no division by 0
i = -1
fmt.Println(unsafe.Sizeof(1 << i)) // 8, no negative shift count
fmt.Println(unsafe.Sizeof(make([]int, i))) // 24, no negative length
fmt.Println(unsafe.Sizeof((*[1]int)([]int{}))) // 8, no converting to bigger array
fmt.Println(unsafe.Sizeof((func() int32)(nil)())) // 4, no function call
fmt.Println(unsafe.Sizeof(<-(chan int64)(nil))) // 8, no receiving
var a, b interface{} = []int{}, []int{}
fmt.Println(unsafe.Sizeof(a == b)) // 1, no comparison
在 Go Playground 上试试这些。