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

[インデックス 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 スライスに以下の値が含まれていました。

  1. int8(-54)
  2. uint8(254)
  3. uint16(48826)

これらの値が binary.LittleEndianbytes.Buffer に書き込まれた場合、それぞれのバイト列は以下のようになります。

  1. int8(-54): 2の補数表現で 0xCA
  2. uint8(254): 0xFE
  3. 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 スライスは以下のようになります。

  1. uint16(61374)
  2. int8(-54)
  3. uint8(254)

これらの値が binary.LittleEndian で書き込まれた場合、それぞれのバイト列は以下のようになります。

  1. uint16(61374): 61374 は16進数で 0xFECF です。リトルエンディアンなので、バイト順は 0xCF 0xFE となります。
  2. int8(-54): 0xCA
  3. 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).