こんにちは
Goのstrconvのパッケージを読んでたらintSizeというものがありました。
const intSize = 32 << (^uint(0) >> 63)
intSizeはAtoiメソッド内で使用されています。
if intSize == 32 && (0 < sLen && sLen < 10) || intSize == 64 && (0 < sLen && sLen < 19)
見た感じintSizeには32か64が代入されるであろうということは分かるのですが、なぜその式になるのかが分からなったので調べてみました。
<<と>>はビット演算子です。<<が左シフト演算で>>が右シフト演算です。
^はビット演算(XOR)です。
使い方はこんな感じ。
package main
import "fmt"
const (
A uint8 = 44
)
func main() {
a := fmt.Sprintf("2進数: %b, 10進数: %d", A, A)
fmt.Println(a)
// 2進数: 00101100, 10進数: 44
l := A << 2
b := fmt.Sprintf("2進数: %b, 10進数: %d", l, l)
fmt.Println(b)
// 2進数: 10110000, 10進数: 176
r := A >> 2
c := fmt.Sprintf("2進数: %b, 10進数: %d", r, r)
fmt.Println(c)
// 2進数: 1011, 10進数: 11
d := fmt.Sprintf("2進数: %b, 10進数: %d", ^A, ^A)
fmt.Println(d)
// 2進数: 11010011, 10進数: 211
}
^は整数演算子としても用意されていて反転の意味になります。44の2進数、00101100を反転すると11010011になります。
公式ではこのように書かれています。
^x bitwise complement is m ^ x with m = “all bits set to 1” for unsigned x and m = -1 for signed x
mには毎回1がセットされ、1ビット毎に排他的論理和演算を行っています。
排他的論理和演算は
0 XOR 0 = 0 0 XOR 1 = 1 1 XOR 0 = 1 1 XOR 1 = 0
という性質を持ちます。
先程の^Aでいうと
1 ^ 0 = 1 1 ^ 0 = 1 1 ^ 1 = 0 1 ^ 0 = 1 1 ^ 1 = 0 1 ^ 1 = 0 1 ^ 0 = 1 1 ^ 0 = 1
を内部で行っており、結果11010011となります。
ここまでは分かれば式で何が行われているのかが分かります。
それでは元のソースコードに戻ります。
const intSize = 32 << (^uint(0) >> 63)
最初に実行されるのは
(^uint(0) >> 63)
の部分でその後に
32 << 上記の計算結果
が実行されます。
uintは環境依存で、32bitか64bitになります。
下記の2つがそれぞれの計算結果になります。
uintが32bitの場合
uint(0) 32bit0埋めにする 0000 0000 0000 0000 0000 0000 0000 0000 ^uint(0) 反転する 1111 1111 1111 1111 1111 1111 1111 1111 ^uint(0) >> 63 右シフト演算で63bitシフトさせる。結果0になる 0000 0000 0000 0000 0000 0000 0000 0000 左シフト演算 32 << 0 = 32 intSize = 32
uintが64bitの場合
uint(0) 64bit0埋めにする 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ^uint(0) 反転する 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 ^uint(0) >> 63 右シフト演算で63bitシフトさせる。結果1になる 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 左シフト演算 32 << 1 = 64 intSize = 64
結果intSizeには32か64が代入されます。
スマート!!
最初見た時はよく分からなかったのですが、調べてみたらとても面白かったです。
引き続きGoのソースリーディングはしていくので、また面白いものがあったらブログに書いていこうと思います。









