英文:
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
}
Why doesn't this code
unsafe.Sizeof(*i)
cause a runtime panic?
答案1
得分: 6
Alignof
、Offsetof
和Sizeof
的调用是编译时常量表达式,类型为uintptr
。
这些函数在编译时进行求值,运行时不会发生实际的解引用操作。
这是因为只需要指向的值的信息,而不需要实际的解引用操作。
在unsafe.Sizeof()
中也有相关说明:
Sizeof的返回值是一个Go常量。
Go中的常量是编译时常量。
还可以参考规范:常量:
常量值由rune、整数、浮点数、虚数或字符串字面量、表示常量的标识符、常量表达式、具有常量结果的转换,或应用于任何值的一些内置函数的结果值,例如
unsafe.Sizeof
,应用于一些表达式的cap
或len
,应用于复数常量的real
和imag
,以及应用于数字常量的complex
。
以下是类似的示例(如果不将它们传递给unsafe.Sizeof()
,则会在运行时引发恐慌或无限期阻塞,但它们可以正常工作):
fmt.Println(unsafe.Sizeof(*(*int8)(nil))) // 1,没有解引用
fmt.Println(unsafe.Sizeof([]int16{}[10])) // 2,没有索引
x := "hi"
fmt.Println(unsafe.Sizeof(x[10])) // 1,没有索引
fmt.Println(unsafe.Sizeof(map[interface{}]int{}[[]int{}])) // 8,没有索引
fmt.Println(unsafe.Sizeof((interface{})(nil).(int16))) // 2,没有类型断言
i := 0
fmt.Println(unsafe.Sizeof(i / i)) // 8,没有除以0
i = -1
fmt.Println(unsafe.Sizeof(1 << i)) // 8,没有负数的移位计数
fmt.Println(unsafe.Sizeof(make([]int, i))) // 24,没有负长度
fmt.Println(unsafe.Sizeof((*[1]int)([]int{}))) // 8,没有转换为更大的数组
fmt.Println(unsafe.Sizeof((func() int32)(nil)())) // 4,没有函数调用
fmt.Println(unsafe.Sizeof(<-(chan int64)(nil))) // 8,没有接收
var a, b interface{} = []int{}, []int{}
fmt.Println(unsafe.Sizeof(a == b)) // 1,没有比较
在Go Playground上尝试这些示例。
英文:
> Calls to Alignof
, Offsetof
, and Sizeof
are compile-time constant expressions of type uintptr
.
These functions are evaluated at compile time, no actual dereferencing happens at runtime.
This is possible because the pointed value is not needed, only information about its type is needed, which does not need dereferencing.
It's also documented at unsafe.Sizeof()
:
> The return value of Sizeof is a Go constant.
Constants in Go are compile-time constants.
Also see Spec: Constants:
> 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.
See similar examples (which without passing them to unsafe.Sizeof()
would panic at runtime or block indefinitely, but they work just fine):
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
Try these on the Go Playground.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论