[インデックス 11071] ファイルの概要
このコミットは、Go言語の仕様書(Go Spec)におけるポインタの比較に関する定義を明確化し、特に「ゼロサイズ変数」へのポインタの振る舞いを規定するものです。これまで曖昧だった「location」という概念を削除し、ゼロサイズ変数の定義を追加することで、ポインタ比較のセマンティクスをより厳密にしています。
コミット
spec: pointer comparison for pointers to 0-sized variables
- define "0-sized"
- add clarifying sentence to pointer comparison
- removed notion "location" which was used only in pointer comparisons
and which was never defined
Fixes #2620.
R=r, rsc, iant
CC=golang-dev
https://golang.org/cl/5528053
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1320ce00c44eef3b477f40a409f654ac145cfac5
元コミット内容
commit 1320ce00c44eef3b477f40a409f654ac145cfac5
Author: Robert Griesemer <gri@golang.org>
Date: Mon Jan 9 16:54:24 2012 -0800
spec: pointer comparison for pointers to 0-sized variables
- define "0-sized"
- add clarifying sentence to pointer comparison
- removed notion "location" which was used only in pointer comparisons
and which was never defined
Fixes #2620.
R=r, rsc, iant
CC=golang-dev
https://golang.org/cl/5528053
変更の背景
この変更の背景には、Go言語のポインタ比較に関する仕様の曖昧さがありました。特に、メモリ上でサイズを持たない「ゼロサイズ変数」へのポインタがどのように比較されるべきかについて、明確な定義が不足していました。
Go言語では、空の構造体(struct{}
)や空の配列([0]T
)など、メモリを占有しない型が存在します。これらは「ゼロサイズ型」と呼ばれ、これらの型の変数は「ゼロサイズ変数」となります。これらの変数がメモリ上でどのように配置され、それらへのポインタが比較された場合にどのような結果になるかは、Go言語の初期の仕様では十分に規定されていませんでした。
コミットメッセージにある「Fixes #2620」は、この問題に関するIssueが存在したことを示唆しています。このIssueは、ゼロサイズ変数へのポインタ比較の振る舞いが未定義であること、または直感的でないことによる混乱やバグの可能性を指摘していたと考えられます。
また、以前の仕様ではポインタ比較の際に「location(場所)」という概念が用いられていましたが、この「location」が具体的に何を指すのかが定義されておらず、曖昧さの原因となっていました。このコミットは、この未定義の概念を削除し、より明確な用語と定義に置き換えることを目的としています。
前提知識の解説
Go言語のポインタ
Go言語におけるポインタは、変数のメモリアドレスを指し示す値です。C/C++のポインタと同様に、間接参照(dereference)によってポインタが指すメモリ上の値にアクセスできます。
&
演算子:変数のアドレスを取得します。例:p := &x
*
演算子:ポインタが指す値にアクセスします(間接参照)。例:v := *p
ポインタは、主に以下の目的で使用されます。
- 関数間で大きなデータをコピーせずに渡す(パフォーマンス向上)。
- 関数内で引数の値を変更する。
- データ構造をリンクする(例: リンクリスト、ツリー)。
ポインタの比較
Go言語では、ポインタ値は比較可能です。
p1 == p2
:p1
とp2
が同じ変数を指しているか、または両方がnil
である場合にtrue
を返します。p1 != p2
:上記以外の場合にtrue
を返します。
ゼロサイズ型とゼロサイズ変数
Go言語には、メモリ上でサイズを占有しない型が存在します。これらを「ゼロサイズ型」と呼びます。 代表的なゼロサイズ型は以下の通りです。
- 空の構造体:
struct{}
- 要素を持たない配列:
[0]T
(Tは任意の型)
これらの型の変数は「ゼロサイズ変数」と呼ばれます。ゼロサイズ変数はメモリを消費しないため、コンパイラやランタイムはこれらの変数を最適化し、同じアドレスを割り当てたり、全くメモリを割り当てなかったりすることがあります。
例えば、var a struct{}
と var b struct{}
という2つのゼロサイズ変数があった場合、これらは異なる変数として宣言されていますが、メモリ上では同じアドレスを共有する可能性があります。これは、それらがデータを保持せず、区別するためのメモリ領域が不要であるためです。
Go言語の仕様書 (Go Spec)
Go言語の仕様書は、Go言語の構文、セマンティクス、標準ライブラリの振る舞いを正式に定義した文書です。Go言語のコンパイラやランタイム、ツールはすべてこの仕様書に基づいて実装されます。このコミットは、この仕様書の内容を直接変更するものです。
技術的詳細
このコミットの技術的詳細は、Go言語のポインタ比較のセマンティクスを、特にゼロサイズ変数に関して厳密に定義し直す点にあります。
-
「location」概念の削除と「variable」への置き換え: 以前のGo Specでは、「Two pointer values are equal if they point to the same location or if both have value
nil
.」と記述されていました。しかし、「location」という用語はGo Spec内で明確に定義されておらず、その意味が曖昧でした。このコミットでは、「location」を「variable(変数)」に置き換えることで、ポインタが指す対象をより具体的にしました。Go言語において「変数」は明確に定義された概念であり、この変更によりポインタ比較の定義がより厳密になります。 -
ゼロサイズ変数の定義の追加: Go Specに新たにゼロサイズ変数の定義が追加されました。 「A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.」 この定義は、どのような型がゼロサイズであるかを明確にし、さらに重要な点として「Two distinct zero-size variables may have the same address in memory.(2つの異なるゼロサイズ変数は、メモリ上で同じアドレスを持つ可能性がある)」という振る舞いを明示しています。これは、コンパイラがゼロサイズ変数を最適化する際に、異なる変数であっても同じメモリ位置を割り当てることが許容されることを意味します。
-
ゼロサイズ変数へのポインタ比較に関する明確化: ポインタ比較の定義に以下の文が追加されました。 「Pointers to distinct zero-size variables may or may not be equal.」 これは、異なるゼロサイズ変数へのポインタが比較された場合、その結果が
true
(等しい)になることもfalse
(等しくない)になることもあり得る、ということを明確にしています。つまり、Go言語の仕様としては、その結果を保証しない(実装依存である)という立場を取ることを示しています。この「may or may not be equal」という記述は非常に重要です。これは、プログラマがゼロサイズ変数へのポインタの等価性に依存したコードを書くべきではないことを示唆しています。コンパイラやランタイムの最適化によって、同じアドレスを指すこともあれば、異なるアドレスを指すこともあるため、その結果は予測不可能であると考えるべきです。
この変更により、Go言語のポインタ比較のセマンティクスがより堅牢になり、特にゼロサイズ変数を扱う際の未定義の振る舞いが解消されました。これにより、異なるGoコンパイラや異なる実行環境間での互換性が向上し、プログラマがより安全にコードを記述できるようになります。
コアとなるコードの変更箇所
変更は doc/go_spec.html
ファイルに対して行われています。
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,5 +1,5 @@
<!-- title The Go Programming Language Specification -->
-<!-- subtitle Version of December 15, 2011 -->
+<!-- subtitle Version of January 9, 2012 -->
<!--
TODO
@@ -13,7 +13,6 @@ TODO
[ ] should probably write something about evaluation order of statements even
though obvious
[ ] review language on implicit dereferencing
-[ ] clarify what it means for two functions to be "the same" when comparing them
-->
@@ -2957,7 +2956,8 @@ These terms and the result of the comparisons are defined as follows:\n \n <li>
Pointer values are comparable.
- Two pointer values are equal if they point to the same <code>location</code> or if both have value <code>nil</code>.\n+\tTwo pointer values are equal if they point to the same <code>variable</code> or if both have value <code>nil</code>.\n+\tPointers to distinct <a href="#Size_and_alignment_guarantees">zero-size</a> variables may or may not be equal.\n </li>
\n <li>
@@ -5348,6 +5348,11 @@ The following minimal alignment properties are guaranteed:\n </li>
</ol>\n \n+<p>\n+A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.\n+</p>\n+\n+\n <span class=\"alert\">\n <h2 id=\"Implementation_differences\">Implementation differences - TODO</h2>\n <ul>\n```
## コアとなるコードの解説
このコミットによる `doc/go_spec.html` の変更は、Go言語の仕様書におけるポインタ比較とゼロサイズ変数の定義を直接修正しています。
1. **ポインタ比較の定義の変更 (L2957-L2960)**:
* 変更前: `Two pointer values are equal if they point to the same <code>location</code> or if both have value <code>nil</code>.`
* 変更後: `Two pointer values are equal if they point to the same <code>variable</code> or if both have value <code>nil</code>.`
* `location` という曖昧な用語が `variable` という明確な用語に置き換えられました。これにより、ポインタが指す対象が「変数」であることが明確になり、仕様の厳密性が向上しました。
* 追加: `Pointers to distinct <a href="#Size_and_alignment_guarantees">zero-size</a> variables may or may not be equal.`
* この新しい文は、異なるゼロサイズ変数へのポインタが比較された場合、その等価性が保証されないことを明示しています。これは、コンパイラがこれらの変数を最適化し、同じメモリ位置に配置する可能性があるためです。プログラマは、この非決定的な振る舞いを考慮してコードを記述する必要があります。
2. **ゼロサイズ変数の定義の追加 (L5348-L5352)**:
* 新たに `<p>` タグで囲まれた段落が追加されました。
* `A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero.`
* ゼロサイズ型(構造体や配列)の正式な定義が提供されました。これは、フィールドや要素がゼロサイズでないものを一切含まない場合にゼロサイズとなることを示しています。
* `Two distinct zero-size variables may have the same address in memory.`
* この文は、異なるゼロサイズ変数であっても、メモリ上で同じアドレスを共有する可能性があるという重要な実装上の特性を明示しています。これは、ポインタ比較の非決定的な振る舞いの根拠となります。
これらの変更により、Go言語のポインタ比較のセマンティクスがより明確になり、特にゼロサイズ変数を扱う際のプログラマの混乱を避けるための重要な指針が提供されました。
## 関連リンク
* Go Issue #2620: [https://github.com/golang/go/issues/2620](https://github.com/golang/go/issues/2620)
* Gerrit Change 5528053: [https://golang.org/cl/5528053](https://golang.org/cl/5528053)
## 参考にした情報源リンク
* Go Programming Language Specification: [https://go.dev/ref/spec](https://go.dev/ref/spec)