1 回答

TA貢獻1824條經驗 獲得超5個贊
你AlignSize的值為 2 的冪。在二進制表示中,它包含一個1位,后跟全零:
fmt.Printf("%b", AlignSize) // 1000000000000
由 分配的切片make()可能具有或多或少隨機的內存地址,由二進制隨機跟隨的 1 和 0 組成;或者更準確地說是其后備數組的起始地址。
由于您分配了所需大小的兩倍,因此可以保證后備數組將覆蓋一個地址空間,該地址空間的中間某處的地址以與AlignSize的二進制表示形式一樣多的零結尾,并且BlockSize數組中的空間以此開頭. 我們要找到這個地址。
這就是Alignment()函數的作用。它使用 獲取后備數組的起始地址&block[0]。在 Go 中沒有指針運算,所以為了做類似的事情,我們必須將指針轉換為整數(當然有整數運算)。為了做到這一點,我們必須將指針轉換為unsafe.Pointer:所有指針都可以轉換為這種類型,并且unsafe.Pointer可以轉換為uintptr(這是一個足夠大的無符號整數來存儲指針值的未解釋位),在其上-是一個整數——我們可以進行整數運算。
我們對值使用按位與uintptr(AlignSize-1)。由于AlignSize是 2 的冪(包含1一位后跟零),因此減一的數字是二進制表示中全是 1 的數字,與尾隨零的數量一樣多AlignSize??催@個例子:
x := 0b1010101110101010101
fmt.Printf("AlignSize : %22b\n", AlignSize)
fmt.Printf("AlignSize-1 : %22b\n", AlignSize-1)
fmt.Printf("x : %22b\n", x)
fmt.Printf("result of & : %22b\n", x&(AlignSize-1))
輸出:
AlignSize : 1000000000000
AlignSize-1 : 111111111111
x : 1010101110101010101
result of & : 110101010101
因此,的結果&是偏移量,如果您從中減去該偏移量AlignSize,您將得到一個地址,其尾隨零的數量與AlignSize它本身一樣多:結果與 的倍數“對齊” AlignSize。
所以我們將使用file從 開始的切片部分offset,我們只需要BlockSize:
file = file[offset : offset+BlockSize]
編輯:
查看您嘗試打印步驟的修改代碼:我得到如下輸出:
Pointer: 0xc0000b6000
Unsafe pointer: 0xc0000b6000
Unsafe pointer, uintptr: 824634466304
Unpersand: 0
Cast to int: 0
Return is: 0
Content is:
注意這里沒有任何改變。簡單地,fmt包使用十六進制表示形式打印指針值,前綴為0x. uintptr值打印為整數,使用十進制表示。這些值是相等的:
fmt.Println(0xc0000b6000, 824634466304) // output: 824634466304 824634466304
另請注意,其余部分是0因為在我的情況下0xc0000b6000已經是 的倍數4096,在二進制中是1100000000000000000100001110000000000000。
編輯#2:
當您用于fmt.Println()調試部分計算時,這可能會改變逃逸分析并可能會改變切片的分配(從堆棧到堆)。這也取決于使用的 Go 版本。不要依賴于你的切片被分配在一個(已經)對齊到AlignSize.
- 1 回答
- 0 關注
- 123 瀏覽
添加回答
舉報