KDOC 418: 実行時のオーバーヘッドなしで型のサイズを判定する

この文書のステータス

  • 作成
    • 2025-07-24 貴島
  • レビュー
    • 2025-07-30 貴島

概要

CPUアーキテクチャによって、型のサイズは異なることがある。実行時のオーバーヘッドなしで判定しているのをGo言語自体のソースコードで見かけた。

constなのでコンパイル時に、ビルド成果物へ値が埋め込まれる。実行時のオーバーヘッドがない。

const uintSize = 32 << (^uint(0) >> 63) // 32 or 64

ビット演算に慣れてないので、一瞬でわからない。確認する。

  • ^ でビット反転する
  • >> で右ビット演算する
  • << で左ビット演算する

中心になるアイデアは、すべてのビットに1が立つとビットサイズの違いが現れるということだ。分解して見る。

import "fmt"
func main() {
  fmt.Printf("%b\n", uint(0))
  fmt.Printf("%b\n", ^uint(0))

  // ^uint(0) >> 63 の結果、32bit環境では 0 に、64bit環境では 1 になる
  fmt.Printf("%d\n", 32 << 0) // 移動しないので32のまま
  fmt.Printf("%d\n", 32 << 1) // 1だけ左シフトする。つまり32(2の5乗)から64(2の6乗)になる
}
0
1111111111111111111111111111111111111111111111111111111111111111
32
64

ビットシフト演算子の両辺どちらが移動量かわからなくなるので確認する。移動元、オペレータ、移動量の位置関係は同じで、矢印の向きがそのまま移動の向きになっている。

import "fmt"
func main() {
  fmt.Printf("%b\n", 0b0010 << 1)
  fmt.Printf("%b\n", 0b0010 >> 1)
}
100
1

関連

なし。