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

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

このコミットは、Go言語のドキュメントとサンプルコードにおいて、Cgo(GoとC言語の相互運用機能)に関する記事で使用されているC標準ライブラリの乱数生成関数を、より移植性の高いC90標準の関数に修正するものです。具体的には、random()srandom()rand()srand() に置き換えています。

コミット

commit 022818c142ebc62da9a0e3a86c728ab36c047027
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Jun 4 01:40:53 2013 +0800

    doc/articles: use C90 standard functions in the cgo article.
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/9953043

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

https://github.com/golang/go/commit/022818c142ebc62da9a0e3a86c728ab36c047027

元コミット内容

doc/articles: use C90 standard functions in the cgo article.

変更の背景

この変更の背景には、C言語の標準ライブラリ関数における移植性の問題があります。random()srandom() 関数は、主にBSD系(Unix-like)システムで利用される乱数生成関数であり、POSIX標準の一部ではありますが、C90(ANSI C)標準には含まれていません。一方、rand()srand() 関数はC90標準で定義されており、より広範なシステムで利用可能です。

Go言語のドキュメント、特にCgoに関する記事は、GoとC言語の連携方法を説明する上で、可能な限り多くの環境で動作する汎用的な例を提供することが重要です。random()srandom() を使用した例は、Windowsなどの非Unix系システムや、古いCコンパイラ環境ではコンパイルエラーやリンクエラーを引き起こす可能性がありました。

このコミットは、ドキュメントの正確性と移植性を向上させ、より多くの読者がCgoの例を自身の環境で試せるようにするために行われました。これにより、Go言語の学習者がCgoの概念を理解する上で、環境依存の問題に遭遇する可能性を減らすことができます。

前提知識の解説

Cgo

Cgoは、GoプログラムからC言語のコードを呼び出すためのGo言語の機能です。Goのソースファイル内にC言語のコードを直接記述したり、既存のCライブラリをリンクしたりすることができます。Cgoを使用することで、Go言語では実装が難しい低レベルの操作や、既存のC言語資産の再利用が可能になります。

Cgoでは、C言語の関数や型は C パッケージを通じてアクセスされます。例えば、C言語の rand() 関数を呼び出すには C.rand() と記述します。また、C言語の型とGo言語の型の間で変換が必要になる場合があります(例: C.uint(i))。

C言語の乱数生成関数

C言語には、主に2種類の擬似乱数生成関数群が存在します。

  1. rand()srand() (C90標準)

    • rand(): 擬似乱数を生成し、0 から RAND_MAX までの整数を返します。RAND_MAX<stdlib.h> で定義されるマクロで、最低でも32767です。
    • srand(unsigned int seed): rand() が生成する乱数列のシード(初期値)を設定します。同じシード値を与えると、常に同じ乱数列が生成されます。通常、異なる乱数列を得るために、プログラムの起動時に一度だけ time(NULL) などをシードとして使用します。
    • 特徴: C90標準で定義されており、非常に高い移植性を持っています。しかし、生成される乱数の品質(統計的特性)は、random() に比べて劣るとされることがあります。特に、下位ビットのランダム性が低い、周期が短いといった問題が指摘されることがあります。
  2. random()srandom() (POSIX/BSD拡張)

    • random(): 擬似乱数を生成し、long 型の値を返します。rand() よりも広い範囲の値を生成し、一般的に rand() よりも高品質な乱数を生成するとされています。
    • srandom(unsigned int seed): random() が生成する乱数列のシードを設定します。
    • 特徴: POSIX標準の一部であり、Unix-likeシステム(Linux, macOS, BSDなど)で広く利用されています。しかし、Windowsなどのシステムでは標準で提供されていないため、移植性に欠けます。

このコミットは、Goのドキュメントの例が、より多くの環境で動作するように、移植性の高い rand()srand() を採用したものです。

技術的詳細

このコミットの技術的な変更点は、Go言語のCgoに関するドキュメントと、それに付随するサンプルコードにおいて、C言語の乱数生成関数の呼び出しを random/srandom から rand/srand へと変更したことです。

具体的には、以下のファイルが変更されています。

  • doc/articles/c_go_cgo.html: Cgoに関する記事のHTMLファイル。
  • doc/progs/cgo1.go: Cgoのサンプルコード1。
  • doc/progs/cgo2.go: Cgoのサンプルコード2。

HTMLドキュメントでは、Cgoの例としてC言語の乱数生成関数をGoから呼び出す方法が説明されています。この説明文中で参照されている関数名が random から rand へ、srandom から srand へと変更されました。また、random 関数が long 型の値を返すという記述が、rand 関数が int 型の値を返すという記述に修正されています。これは、C90標準の rand() 関数が int を返すのに対し、POSIXの random() 関数が long を返すという違いを反映したものです。

Goのサンプルコード (cgo1.gocgo2.go) では、実際にC言語の関数を呼び出す部分が修正されました。C.random()C.rand() に、C.srandom()C.srand() に変更されています。また、cgo2.go では C.long 型の変数 rC.int 型に変更されています。これは、Goの int 型に変換する前に、C言語側で受け取る値の型を正確に反映させるためです。

これらの変更により、ドキュメントの記述とサンプルコードがC90標準に準拠し、より多くのプラットフォームでの互換性が確保されました。

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

doc/articles/c_go_cgo.html

--- a/doc/articles/c_go_cgo.html
+++ b/doc/articles/c_go_cgo.html
@@ -11,8 +11,8 @@ single Go package.
 
 <p>
 To lead with an example, here's a Go package that provides two functions -
-<code>Random</code> and <code>Seed</code> - that wrap C's <code>random</code>
-and <code>srandom</code> functions.
+<code>Random</code> and <code>Seed</code> - that wrap C's <code>rand</code>
+and <code>srand</code> functions.
 </p>
 
 {{code "/doc/progs/cgo1.go" `/package rand/` `/END/`}}
@@ -30,14 +30,14 @@ name space.
 
 <p>
 The <code>rand</code> package contains four references to the <code>C</code>
-package: the calls to <code>C.random</code> and <code>C.srandom</code>, the
+package: the calls to <code>C.rand</code> and <code>C.srand</code>, the
 conversion <code>C.uint(i)</code>, and the <code>import</code> statement.
 </p>
 
 <p>
 The <code>Random</code> function calls the standard C library's <code>random</code>
-function and returns the result.  In C, <code>random</code> returns a value of the
-C type <code>long</code>, which cgo represents as the type <code>C.long</code>.
+function and returns the result.  In C, <code>rand</code> returns a value of the
+C type <code>int</code>, which cgo represents as the type <code>C.int</code>.
 It must be converted to a Go type before it can be used by Go code outside this
 package, using an ordinary Go type conversion:
 </p>
@@ -54,7 +54,7 @@ the type conversion more explicitly:
 <p>
 The <code>Seed</code> function does the reverse, in a way. It takes a
 regular Go <code>int</code>, converts it to the C <code>unsigned int</code>
-type, and passes it to the C function <code>srandom</code>.
+type, and passes it to the C function <code>srand</code>.
 </p>
 
 {{code "/doc/progs/cgo1.go" `/func Seed/` `/END/`}}

doc/progs/cgo1.go

--- a/doc/progs/cgo1.go
+++ b/doc/progs/cgo1.go
@@ -12,12 +12,12 @@ import "C"
 
 // STOP OMIT
 func Random() int {
-	return int(C.random())
+	return int(C.rand())
 }
 
 // STOP OMIT
 func Seed(i int) {
-	C.srandom(C.uint(i))
+	C.srand(C.uint(i))
 }
 
 // END OMIT

doc/progs/cgo2.go

--- a/doc/progs/cgo2.go
+++ b/doc/progs/cgo2.go
@@ -11,13 +11,13 @@ package rand2
 import "C"
 
 func Random() int {
-	var r C.long = C.random()
+	var r C.int = C.rand()
 	return int(r)
 }
 
 // STOP OMIT
 func Seed(i int) {
-	C.srandom(C.uint(i))
+	C.srand(C.uint(i))
 }
 
 // END OMIT

コアとなるコードの解説

doc/articles/c_go_cgo.html の変更点

  • 関数名の変更:
    • C's random and srandom functionsC's rand and srand functions に変更されました。これは、記事内で説明されているCgoの例が、どのC関数をラップしているかを明確にするためです。
  • Cgo呼び出しの記述変更:
    • calls to C.random and C.srandomcalls to C.rand and C.srand に変更されました。これは、Goコード内でのC関数呼び出しの記述を修正したものです。
  • 戻り値の型の説明変更:
    • In C, random returns a value of the C type long, which cgo represents as the type C.long.In C, rand returns a value of the C type int, which cgo represents as the type C.int. に変更されました。これは、random()rand() の戻り値の型が異なる(long vs int)ことを正確に反映させるための重要な修正です。Cgoでは、C言語の型とGo言語の型の間で適切なマッピングが行われるため、この記述の正確性は重要です。
  • Seed 関数の引数の説明変更:
    • passes it to the C function srandompasses it to the C function srand に変更されました。

これらの変更は、ドキュメントの内容を実際のコードの変更と一致させ、読者に正確な情報を提供することを目的としています。

doc/progs/cgo1.go および doc/progs/cgo2.go の変更点

両方のGoファイルで、C言語の乱数生成関数を呼び出す部分が修正されています。

  • Random() 関数内:
    • return int(C.random())return int(C.rand()) に変更されました。これにより、Goの Random 関数がC90標準の rand() 関数を呼び出すようになります。
  • Seed() 関数内:
    • C.srandom(C.uint(i))C.srand(C.uint(i)) に変更されました。これにより、Goの Seed 関数がC90標準の srand() 関数を呼び出すようになります。
  • doc/progs/cgo2.go の追加変更:
    • var r C.long = C.random()var r C.int = C.rand() に変更されました。これは、random()long を返すのに対し、rand()int を返すため、Cgoで受け取る変数の型を C.long から C.int に修正したものです。この変更は、C言語の型とGo言語の型の間での正確な型変換を保証するために必要です。

これらのコード変更により、GoのCgoサンプルプログラムが、より移植性の高いC90標準の乱数生成関数を使用するようになり、異なるオペレーティングシステムやコンパイラ環境での互換性が向上しました。

関連リンク

参考にした情報源リンク