Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 14364] ファイルの概要

このコミットは、Go言語のテストスイート内の test/index.go ファイルに対する変更です。具体的には、int 型のサイズに関するテストロジックが修正されています。

コミット

commit 3e50372f1ff0229aa8c42cde8f5cd0b6357b605d
Author: Ian Lance Taylor <iant@golang.org>
Date:   Thu Nov 8 15:43:28 2012 -0800

    test: change index.go to test size of int, not GOARCH == "amd64"
    
    Fixes the test to work correctly on other platforms with
    64-bit ints, like Alpha.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/6822099

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/3e50372f1ff0229aa8c42cde8f5cd0b6357b605d

元コミット内容

このコミットの目的は、test/index.go 内のテストが、特定のアーキテクチャ(amd64)に依存するのではなく、int 型の実際のサイズに基づいて動作するように修正することです。これにより、Alphaプロセッサのような64ビットintを持つ他のプラットフォームでもテストが正しく機能するようになります。

変更の背景

Go言語はクロスプラットフォーム対応を重視しており、様々なアーキテクチャで動作するように設計されています。以前の test/index.go のテストコードでは、int 型のサイズが64ビットであるかどうかを runtime.GOARCH == "amd64" という条件で判断していました。しかし、これは amd64 アーキテクチャが64ビットシステムであるという一般的な仮定に基づいています。

問題は、amd64 以外のアーキテクチャでも int 型が64ビットである場合があることです。例えば、Alphaプロセッサは64ビットアーキテクチャであり、その上でGoが動作する場合、int 型も64ビットになります。このような環境では、runtime.GOARCH == "amd64" という条件は偽となるため、int 型のサイズが64ビットであるにもかかわらず、テストが意図したパスを通らない、あるいは誤った結果を出す可能性がありました。

このコミットは、このようなアーキテクチャ依存の問題を解決し、テストの移植性と正確性を向上させるために行われました。

前提知識の解説

  • Go言語の int: Go言語の int 型は、その実行環境のCPUアーキテクチャに依存してサイズが変わる整数型です。32ビットシステムでは32ビット(4バイト)、64ビットシステムでは64ビット(8バイト)のサイズを持ちます。これは、C言語の int 型が通常32ビットであるのとは異なり、Go言語の設計思想の一つです。
  • runtime.GOARCH: Go言語の runtime パッケージに含まれる変数で、現在のプログラムが実行されているシステムのアーキテクチャ(例: "amd64", "arm", "386" など)を示す文字列を返します。
  • unsafe.Sizeof: Go言語の unsafe パッケージに含まれる関数で、任意の型の変数がメモリ上で占めるバイト数を返します。これはコンパイル時に評価される定数です。unsafe パッケージは、Goの型安全性を迂回する低レベルな操作を可能にするため、通常は注意して使用されますが、このようなシステムレベルの情報を取得する際には有用です。
  • コンパイル時エラーと実行時エラー: プログラミングにおいて、エラーは大きく分けてコンパイル時と実行時に発生します。
    • コンパイル時エラー: ソースコードが言語の文法規則や型規則に違反している場合に、コンパイラがプログラムをビルドする際に検出するエラーです。例えば、存在しない変数を参照したり、型が一致しない演算を行ったりする場合などです。
    • 実行時エラー: プログラムが正常にコンパイルされ、実行された後に発生するエラーです。例えば、ゼロ除算、配列の範囲外アクセス、メモリ不足などです。
  • Go言語における大きな数値リテラル: Go言語では、整数リテラルが int 型の最大値を超える場合、通常はコンパイル時エラーとなります。しかし、int 型が64ビットである環境では、32ビット環境では大きすぎると判断される数値リテラルでも int 型に収まるため、コンパイルエラーにならずに処理されることがあります。このコミットで修正されているテストは、この挙動を検証するものです。

技術的詳細

変更前のコードでは、i == "i64big" || i == "i64bigger" という条件(これは非常に大きな整数リテラルをテストしていることを示唆しています)と runtime.GOARCH == "amd64" という条件がAND結合されていました。これは、「もし amd64 アーキテクチャであれば、これらの大きな数値は int に収まるため、コンパイル時に拒否されない」という仮定に基づいています。

しかし、この仮定は amd64 以外の64ビットアーキテクチャ(例: Alpha)では破綻します。これらのプラットフォームでは int 型が64ビットであるため、i64bigi64bigger といった大きな数値リテラルも int に収まりますが、runtime.GOARCH == "amd64" は偽となるため、テストのロジックが正しく適用されませんでした。

このコミットでは、runtime.GOARCH == "amd64"unsafe.Sizeof(int(0)) > 4 に変更しています。

  • int(0)int 型のゼロ値です。
  • unsafe.Sizeof(int(0)) は、int 型がメモリ上で占めるバイト数を返します。
  • > 4 という条件は、int 型のサイズが4バイト(32ビット)よりも大きい、つまり8バイト(64ビット)であることを意味します。

この変更により、テストは特定のアーキテクチャ名に依存するのではなく、int 型の実際のサイズに基づいて動作するようになります。これにより、amd64 であろうとAlphaであろうと、int 型が64ビットであるすべてのプラットフォームでテストが正しく機能するようになります。これは、Go言語の移植性を高める上で重要な修正です。

コアとなるコードの変更箇所

--- a/test/index.go
+++ b/test/index.go
@@ -13,7 +13,7 @@ import (
 	"bufio"
 	"fmt"
 	"os"
-	"runtime"
+	"unsafe"
 )
 
 const prolog = `
@@ -214,9 +214,10 @@ func main() {
 				// the next pass from running.
 				// So run it as a separate check.
 				thisPass = 1
-			} else if a == "s" && n == "" && (i == "i64big" || i == "i64bigger") && runtime.GOARCH == "amd64" {
-				// On amd64, these huge numbers do fit in an int, so they are not
-				// rejected at compile time.
+			} else if a == "s" && n == "" && (i == "i64big" || i == "i64bigger") && unsafe.Sizeof(int(0)) > 4 {
+				// If int is 64 bits, these huge
+				// numbers do fit in an int, so they
+				// are not rejected at compile time.
 				thisPass = 0
 			} else {
 				thisPass = 2

コアとなるコードの解説

変更は test/index.go ファイルの main 関数内の条件分岐にあります。

  • 変更前:

    } else if a == "s" && n == "" && (i == "i64big" || i == "i64bigger") && runtime.GOARCH == "amd64" {
        // On amd64, these huge numbers do fit in an int, so they are not
        // rejected at compile time.
        thisPass = 0
    

    この行では、a == "s"n == ""(i == "i64big" || i == "i64bigger") という条件に加えて、runtime.GOARCH == "amd64" というアーキテクチャ固有のチェックが行われていました。コメントにもあるように、amd64 環境では大きな数値リテラルが int に収まるため、コンパイルエラーにならないことを期待していました。

  • 変更後:

    } else if a == "s" && n == "" && (i == "i64big" || i == "i64bigger") && unsafe.Sizeof(int(0)) > 4 {
        // If int is 64 bits, these huge
        // numbers do fit in an int, so they
        // are not rejected at compile time.
        thisPass = 0
    

    runtime.GOARCH == "amd64" の部分が unsafe.Sizeof(int(0)) > 4 に置き換えられました。これにより、テストの条件が「現在のシステムで int 型が64ビット(4バイトより大きい)であるか」という、より汎用的なものになりました。この変更により、amd64 以外の64ビットアーキテクチャでも、このテストパスが正しく評価されるようになります。

また、この変更に伴い、runtime パッケージのインポートが不要になり、代わりに unsafe パッケージがインポートされています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコードリポジトリ (GitHub)
  • Go言語のIssueトラッカーおよびコードレビューシステム (Gerrit)
  • 一般的なプログラミングにおけるコンパイル時と実行時の概念に関する情報