[インデックス 12242] ファイルの概要
このコミットは、Go言語の標準ライブラリ encoding/binary
パッケージ内の example_test.go
ファイルに対する変更です。具体的には、ExampleWrite_multi
関数のテスト例において、binary.Write
を使用して複数の異なる型のデータをバイト列に書き込む際の出力例が修正されています。
コミット
encoding/binary: better example
leave that joke to Java.
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5695080
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fa33fdbc7dc29f5c24c9a82868cbaf076ba59214
元コミット内容
commit fa33fdbc7dc29f5c24c9a82868cbaf076ba59214
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Tue Feb 28 10:15:23 2012 +1100
encoding/binary: better example
leave that joke to Java.
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5695080
---
src/pkg/encoding/binary/example_test.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)\n
変更の背景
このコミットの背景には、encoding/binary
パッケージの ExampleWrite_multi
関数における出力例の改善があります。元の例では、出力されるバイト列の16進数表現が cafebabe
とコメントされていました。CAFEBABE
は、Javaのクラスファイルフォーマットの「マジックナンバー」として広く知られている16進数値です。これは、Java仮想マシンがクラスファイルを識別するために使用する特別な署名です。
コミットメッセージの「leave that joke to Java.」という記述は、この cafebabe
という出力がJavaを連想させるものであり、Go言語の例としては適切ではない、あるいは意図しないジョークになってしまっているという認識を示唆しています。Go言語の公式ライブラリの例として、特定の他言語の内部的なマジックナンバーを連想させるような出力は避けるべきであるという判断があったと考えられます。
そのため、このコミットでは、出力されるバイト列の値を変更し、それに対応するコメントも beefcafe
に修正することで、より汎用的で誤解を招かない例にすることを目的としています。BEEFCAFE
もまた、デバッグやテストで使われることのある16進数のパターンですが、CAFEBABE
ほど特定の技術と強く結びついてはいません。
前提知識の解説
Go言語の encoding/binary
パッケージ
encoding/binary
パッケージは、Go言語において、数値データをバイト列との間で変換するための機能を提供します。これは、ネットワークプロトコル、ファイルフォーマット、または異なるシステム間でのデータ交換など、バイトオーダー(エンディアン)が重要な場面で特に役立ちます。
binary.Write(w io.Writer, order ByteOrder, data interface{}) error
: この関数は、指定されたバイトオーダー(order
)に従って、data
の値をw
に書き込みます。data
は、固定サイズの数値型(int8
,uint8
,int16
,uint16
など)、またはそれらのスライス、あるいはそれらを含む構造体である必要があります。binary.LittleEndian
: リトルエンディアンは、数値の最下位バイト(least significant byte)が最初に格納されるバイトオーダーです。例えば、16進数0x1234
をリトルエンディアンで2バイトに格納する場合、0x34
が先、0x12
が後に続きます。binary.BigEndian
: ビッグエンディアンは、数値の最上位バイト(most significant byte)が最初に格納されるバイトオーダーです。例えば、16進数0x1234
をビッグエンディアンで2バイトに格納する場合、0x12
が先、0x34
が後に続きます。
bytes.Buffer
bytes.Buffer
は、可変長のバイトバッファを実装するGo言語の型です。io.Writer
インターフェースを実装しているため、binary.Write
のような関数がバイト列を書き込むターゲットとして使用できます。メモリ上でバイト列を効率的に構築する際に便利です。
数値型と16進数表現
uint16
: 符号なし16ビット整数型。0から65535までの値を保持できます。int8
: 符号付き8ビット整数型。-128から127までの値を保持できます。負の数は2の補数表現で格納されます。uint8
: 符号なし8ビット整数型。0から255までの値を保持できます。fmt.Printf("%x", ...)
:fmt
パッケージのPrintf
関数は、フォーマットされた出力を生成します。%x
動詞は、数値を小文字の16進数形式で出力するために使用されます。バイトスライスに対して使用すると、各バイトが2桁の16進数として連結されて出力されます。
エンディアンネス (Endianness)
エンディアンネスは、複数バイトで構成されるデータをメモリ上にどのように配置するか、またはネットワーク上でどのように転送するかを決定するバイトオーダーの規則です。
- リトルエンディアン (Little-endian): 最下位バイトが最も小さいアドレスに格納されます。Intel x86アーキテクチャのCPUなどで採用されています。
- ビッグエンディアン (Big-endian): 最上位バイトが最も小さいアドレスに格納されます。ネットワークバイトオーダーとして標準的に使用され、PowerPCやMotorola 68kなどのCPUで採用されていました。
異なるエンディアンを持つシステム間でデータをやり取りする際には、このバイトオーダーの違いを適切に処理しないと、データの解釈が誤る可能性があります。encoding/binary
パッケージは、この問題に対処するためのツールを提供します。
技術的詳細
このコミットの技術的な変更は、src/pkg/encoding/binary/example_test.go
ファイル内の ExampleWrite_multi
関数に集中しています。
元のコードでは、data
スライスに以下の値が含まれていました。
int8(-54)
uint8(254)
uint16(48826)
これらの値が binary.LittleEndian
で bytes.Buffer
に書き込まれた場合、それぞれのバイト列は以下のようになります。
int8(-54)
: 2の補数表現で0xCA
uint8(254)
:0xFE
uint16(48826)
:48826
は16進数で0xBEFA
です。リトルエンディアンなので、バイト順は0xFA 0xBE
となります。
したがって、元のコードが生成するバイト列は [0xCA, 0xFE, 0xFA, 0xBE]
であり、fmt.Printf("%x", buf.Bytes())
の出力は cafefabe
となります。しかし、元のコメントは // Output: cafebabe
となっており、これは実際の出力と異なっていました。
今回のコミットでは、data
スライスの uint16
の値が uint16(48826)
から uint16(61374)
に変更され、その順序も先頭に移動しました。
新しい data
スライスは以下のようになります。
uint16(61374)
int8(-54)
uint8(254)
これらの値が binary.LittleEndian
で書き込まれた場合、それぞれのバイト列は以下のようになります。
uint16(61374)
:61374
は16進数で0xFECF
です。リトルエンディアンなので、バイト順は0xCF 0xFE
となります。int8(-54)
:0xCA
uint8(254)
:0xFE
したがって、新しいコードが生成するバイト列は [0xCF, 0xFE, 0xCA, 0xFE]
であり、fmt.Printf("%x", buf.Bytes())
の出力は cffecafe
となります。コミットでは、この出力に対応するコメントが // Output: beefcafe
に変更されていますが、これもまた実際の出力 cffecafe
とは厳密には一致していません。
この不一致は、例の簡潔さや特定の16進数パターン(beefcafe
)を意図的に示したいという目的のために、厳密な数値計算よりも視覚的な効果を優先した結果である可能性があります。重要なのは、cafebabe
というJava特有のマジックナンバーを連想させる出力を避け、より一般的なバイト列の例に修正したという点です。
この変更は、encoding/binary
パッケージの機能自体には影響を与えず、あくまでテスト例の出力とコメントを修正することで、ドキュメントとしての品質と意図を明確にすることを目的としています。
コアとなるコードの変更箇所
--- a/src/pkg/encoding/binary/example_test.go
+++ b/src/pkg/encoding/binary/example_test.go
@@ -25,9 +25,9 @@ func ExampleWrite() {
func ExampleWrite_multi() {
buf := new(bytes.Buffer)
var data = []interface{}{\n+\t\tuint16(61374),\n \t\tint8(-54),\n \t\tuint8(254),\n-\t\tuint16(48826),\n \t}\n \tfor _, v := range data {\n \t\terr := binary.Write(buf, binary.LittleEndian, v)\n@@ -36,7 +36,7 @@ func ExampleWrite_multi() {\n \t\t}\n \t}\n \tfmt.Printf(\"%x\", buf.Bytes())\n-\t// Output: cafebabe\n+\t// Output: beefcafe\n }\n \n func ExampleRead() {\n```
## コアとなるコードの解説
変更は `ExampleWrite_multi` 関数内の `data` スライスの定義と、その直後の出力コメントにあります。
1. **`data` スライスの変更**:
- 削除された行: `uint16(48826),`
- これは元の例で `uint16` 型の数値 `48826` をバイト列に変換していました。リトルエンディアンでは `0xFA 0xBE` となります。
- 追加された行: `uint16(61374),`
- 新しい例では `uint16` 型の数値 `61374` が追加されました。リトルエンディアンでは `0xCF 0xFE` となります。
- この `uint16(61374)` は、スライス内の最初の要素として配置されています。これにより、出力されるバイト列の順序が変更されます。
2. **出力コメントの変更**:
- 削除された行: `// Output: cafebabe`
- 元の例の期待される出力が `cafebabe` であることを示していました。しかし、前述の通り、実際の出力は `cafefabe` であり、このコメントは不正確でした。
- 追加された行: `// Output: beefcafe`
- 新しい例の期待される出力が `beefcafe` であることを示しています。これもまた、実際の出力 `cffecafe` とは厳密には一致しませんが、`cafebabe` という特定のパターンから離れるという意図が込められています。
この変更により、`binary.Write` が異なる型のデータをどのようにバイト列に変換し、それらを連結するかを示す例が更新されました。特に、`uint16` の値と位置が変更されたことで、最終的なバイト列の構成が変わり、それに合わせて期待される出力のコメントも修正されています。
## 関連リンク
- Go言語 `encoding/binary` パッケージのドキュメント: [https://pkg.go.dev/encoding/binary](https://pkg.go.dev/encoding/binary)
- Go言語 `bytes` パッケージのドキュメント: [https://pkg.go.dev/bytes](https://pkg.go.dev/bytes)
- Go言語 `fmt` パッケージのドキュメント: [https://pkg.go.dev/fmt](https://pkg.go.dev/fmt)
- Go言語のコードレビューシステム (Gerrit) 上の変更リスト: [https://golang.org/cl/5695080](https://golang.org/cl/5695080)
## 参考にした情報源リンク
- Java Class File Format (Oracle Documentation): [https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1) (特にマジックナンバー `0xCAFEBABE` について)
- Endianness (Wikipedia): [https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3)
- 2の補数 (Wikipedia): [https://ja.wikipedia.org/wiki/2%E3%81%AE%E8%A3%9C%E6%95%B0](https://ja.wikipedia.org/wiki/2%E3%81%AE%E8%A3%9C%E6%95%B0)
- Hexadecimal (Wikipedia): [https://ja.wikipedia.org/wiki/%E5%8D%81%E5%85%AD%E9%80%B2%E6%B3%95](https://ja.wikipedia.org/wiki/%E5%8D%81%E5%85%AD%E9%80%B2%E6%B3%95)
- `CAFEBABE` and `BEEFCAFE` in computing contexts (general knowledge, often found in discussions about magic numbers, debugging, or memory patterns).