[インデックス 14845] ファイルの概要
このコミットは、Go言語のcgo
ツールにおけるgccgo
コンパイラに関する特定の挙動を修正するものです。具体的には、src/cmd/cgo/out.go
ファイルが変更されており、cgo
が生成するCコードにおいて、_Ctype_void
の定義と、Goのslice
型やstring
型に関連する内部表現(特に長さを示すフィールド)の扱いがgccgo
の期待する形式に合わせられています。これにより、gccgo
環境下でのcgo
の互換性と正確性が向上します。
コミット
cmd/cgo
: gccgo
向けにintgo
を使用し、void
の戻り値型としてslice
を使用しないようにする。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/eee3dd1292ba1b4282b39e3288239d5259a765b4
元コミット内容
commit eee3dd1292ba1b4282b39e3288239d5259a765b4
Author: Ian Lance Taylor <iant@golang.org>
Date: Wed Jan 9 15:25:46 2013 -0800
cmd/cgo: for gccgo: use intgo, don't use slice as void return type
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7057064
変更の背景
Go言語には、公式のコンパイラであるgc
(Go Compiler)と、GCCのフロントエンドとして実装されたgccgo
の2つの主要なコンパイラがあります。cgo
はGoプログラムからC言語のコードを呼び出すためのツールであり、その過程でGoとCの間でデータ型を変換したり、Cの関数シグネチャをGoのそれにマッピングしたりします。
このコミットが行われた背景には、gc
とgccgo
の間での内部的な型表現の違いがありました。特に、以下の点が問題となっていました。
void
型の表現: C言語のvoid
型は、Go言語には直接対応する型がありません。cgo
はこれをGo側で表現するために_Ctype_void
という型を生成しますが、gc
とgccgo
ではその内部表現が異なっていました。gc
は[0]byte
(長さ0のバイト配列)として表現していましたが、gccgo
はbyte
(単一のバイト)として表現することを期待していました。この不一致が、void
型を扱う際のコンパイルエラーや予期せぬ挙動を引き起こす可能性がありました。- Goの
string
およびslice
の内部表現: Goのstring
型やslice
型は、内部的にデータへのポインタと長さを保持する構造体として表現されます。この長さを示すフィールドの型が、gc
とgccgo
で異なっていました。gc
は通常のint
を使用していましたが、gccgo
はintgo
という特定の型(通常はintptr_t
にマップされる)を期待していました。この不一致は、CコードからGoのstring
やslice
を操作する際に、不正なメモリアクセスやデータ破損につながる可能性がありました。 void
戻り値型としてのslice
の使用:cgo
の内部処理において、特定の状況でvoid
の戻り値型をSlice
(Goのslice
のC表現)として扱ってしまうケースがあったようです。これはセマンティクス的に誤りであり、gccgo
がこれを正しく処理できない可能性がありました。
これらの不一致を解消し、gccgo
環境下でもcgo
が生成するコードが正しくコンパイルされ、期待通りに動作するようにするために、この変更が導入されました。
前提知識の解説
cgo
cgo
は、Go言語のプログラムからC言語のコードを呼び出すためのツールです。Goのソースファイル内にCのコードを直接記述したり、既存のCライブラリをリンクしたりすることを可能にします。cgo
は、GoとCの間の型変換や関数呼び出しの橋渡しとなるコード(スタブコード)を自動生成します。
gcとgccgo
- gc (Go Compiler): Go言語の公式コンパイラであり、Goプロジェクトによって開発・メンテナンスされています。Goのソースコードを直接機械語にコンパイルします。
- gccgo: GCC (GNU Compiler Collection) のフロントエンドとして実装されたGoコンパイラです。GCCの最適化パスやバックエンドを利用できるため、特定のプラットフォームでのパフォーマンスや互換性において利点を持つことがあります。
gc
とは異なる内部的な型表現やABI (Application Binary Interface) を持つことがあります。
intgo
intgo
は、gccgo
コンパイラがGoのint
型やポインタのオフセット、長さなどを表現するために内部的に使用する型です。通常、C言語のintptr_t
にマップされます。intptr_t
は、ポインタを保持できる十分な大きさを持つ整数型であり、システムによって32ビットまたは64ビットになります。gc
ではこれらの用途に通常のint
が使われることが多いですが、gccgo
ではABIの互換性やポータビリティのためにintgo
が導入されています。
_Ctype_void
_Ctype_void
は、cgo
がC言語のvoid
型をGo言語側で表現するために生成する内部的な型です。Cのvoid
は「型なし」を意味し、Goには直接対応する型がありません。このコミット以前は、gc
では[0]byte
(長さ0のバイト配列)として表現されていましたが、gccgo
ではbyte
として表現されるべきでした。
Goのstringとsliceの内部表現
Goのstring
型は、読み取り専用のバイト列へのポインタと、そのバイト列の長さを保持する構造体です。
Goのslice
型は、要素へのポインタ、スライスの長さ(len
)、およびスライスの容量(cap
)を保持する構造体です。
これらの長さや容量を示すフィールドは、C言語側からアクセスされる際に、gc
とgccgo
で期待される型が異なることが問題でした。
技術的詳細
このコミットは、cgo
が生成するCコードにおいて、gc
とgccgo
の間の内部的な型表現の不一致を解消することを目的としています。
-
_Ctype_void
の条件付き定義:src/cmd/cgo/out.go
の変更により、_Ctype_void
の定義が*gccgo
フラグ(gccgo
コンパイラを使用しているかどうかを示す)に基づいて条件付きになりました。*gccgo
がtrue
の場合、_Ctype_void
はbyte
として定義されます。- それ以外の場合(
gc
を使用している場合)、_Ctype_void
は引き続き[0]byte
として定義されます。 - これにより、各コンパイラが期待する
void
型のGo表現が提供され、コンパイルエラーやランタイムエラーが回避されます。
-
intgo
の導入と使用:cPrologGccgo
というCのプロローグコード(gccgo
向けにcgo
が生成するCコードの冒頭部分)にtypedef intptr_t intgo;
が追加されました。これにより、Cコード内でintgo
がintptr_t
のエイリアスとして利用可能になります。- Goの
__go_string
構造体(Goのstring
のC表現)の__length
フィールドの型がint
からintgo
に変更されました。 - Goの
__go_open_array
構造体(Goのslice
のC表現)の__count
および__capacity
フィールドの型がint
からintgo
に変更されました。 __go_byte_array_to_string
関数のlen
引数、GoString
関数のlen
変数、GoStringN
関数のn
引数、GoBytes
関数のn
引数など、Goのstring
やslice
の長さを扱うC関数や変数でint
がintgo
に置き換えられました。- これらの変更により、
gccgo
が期待するstring
やslice
の長さフィールドの型と一致し、GoとCの間でのデータ受け渡しが正しく行われるようになります。
-
void
戻り値型としてのslice
の使用の回避:- コミットメッセージの「don't use slice as void return type」という記述は、具体的なコード変更としては
_Ctype_void
の定義変更とintgo
の使用によって間接的に解決されていると考えられます。void
型が正しくbyte
として扱われることで、誤ってSlice
として解釈されるような状況が解消されたと推測されます。
- コミットメッセージの「don't use slice as void return type」という記述は、具体的なコード変更としては
これらの変更は、cgo
が生成するCコードがgccgo
のABIとより密接に一致するようにすることで、gccgo
環境下でのGoプログラムの安定性と互換性を大幅に向上させます。
コアとなるコードの変更箇所
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -75,7 +75,11 @@ func (p *Package) writeDefs() {
conf.Fprint(fgo2, fset, def.Go)
fmt.Fprintf(fgo2, "\n\n")
}
- fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
+ if *gccgo {
+ fmt.Fprintf(fgo2, "type _Ctype_void byte\n")
+ } else {
+ fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
+ }
if *gccgo {
fmt.Fprintf(fc, cPrologGccgo)
@@ -1062,19 +1066,20 @@ const cPrologGccgo = `
#include <string.h>
typedef unsigned char byte;
+typedef intptr_t intgo;
struct __go_string {
const unsigned char *__data;
- int __length;
+ intgo __length;
};
typedef struct __go_open_array {
void* __values;
- int __count;
- int __capacity;
+ intgo __count;
+ intgo __capacity;
} Slice;
-struct __go_string __go_byte_array_to_string(const void* p, int len);\n
+struct __go_string __go_byte_array_to_string(const void* p, intgo len);\n
struct __go_open_array __go_string_to_byte_array (struct __go_string str);\n
const char *CString(struct __go_string s) {
@@ -1082,15 +1087,15 @@ const char *CString(struct __go_string s) {
}
struct __go_string GoString(char *p) {
-\tint len = (p != NULL) ? strlen(p) : 0;\n
+\tintgo len = (p != NULL) ? strlen(p) : 0;\n
return __go_byte_array_to_string(p, len);\n
}\n
-struct __go_string GoStringN(char *p, int n) {\n
+struct __go_string GoStringN(char *p, intgo n) {\n
return __go_byte_array_to_string(p, n);\n
}\n
-Slice GoBytes(char *p, int n) {\n
+Slice GoBytes(char *p, intgo n) {\n
struct __go_string s = { (const unsigned char *)p, n };\n
return __go_string_to_byte_array(s);\n
}\n
コアとなるコードの解説
src/cmd/cgo/out.go
の変更点
-
_Ctype_void
の定義の条件分岐:- fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\\n") + if *gccgo { + fmt.Fprintf(fgo2, "type _Ctype_void byte\\n") + } else { + fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\\n") + }
この変更は、Go側でCの
void
型を表現する_Ctype_void
の定義を、使用しているコンパイラ(gc
かgccgo
か)に応じて切り替えるものです。*gccgo
がtrue
の場合(gccgo
コンパイラを使用している場合)、_Ctype_void
はbyte
として定義されます。これはgccgo
がvoid
型を単一のバイトとして扱うことを期待しているためです。- それ以外の場合(デフォルトの
gc
コンパイラを使用している場合)、_Ctype_void
は以前と同様に[0]byte
(長さ0のバイト配列)として定義されます。これはgc
がvoid
型をこのように表現するためです。 この条件分岐により、両方のコンパイラでvoid
型の扱いが正しくなります。
-
cPrologGccgo
内のintgo
の導入と使用:cPrologGccgo
は、gccgo
向けにcgo
が生成するCコードの冒頭に挿入されるC言語のコードブロックです。-
typedef intptr_t intgo;
の追加:typedef unsigned char byte; +typedef intptr_t intgo;
intgo
という新しい型が導入され、それがC標準ライブラリのintptr_t
にtypedef
されています。intptr_t
は、ポインタを保持できる十分な大きさを持つ整数型であり、システム(32ビットまたは64ビット)に応じて適切なサイズになります。これにより、Goの内部的な長さやオフセットを表現する際に、ポインタのサイズに合わせた整数型を使用できるようになります。 -
__go_string
構造体の__length
フィールドの型変更:struct __go_string { const unsigned char *__data; - int __length; + intgo __length; };
Goの
string
型がC側で表現される__go_string
構造体の__length
フィールドの型がint
からintgo
に変更されました。これにより、gccgo
が期待するstring
の長さフィールドの型と一致し、GoとCの間でのstring
の受け渡しが正しく行われます。 -
__go_open_array
構造体の__count
と__capacity
フィールドの型変更:typedef struct __go_open_array { void* __values; - int __count; - int __capacity; + intgo __count; + intgo __capacity; } Slice;
Goの
slice
型がC側で表現される__go_open_array
構造体の__count
(長さ)と__capacity
(容量)フィールドの型がint
からintgo
に変更されました。これもgccgo
のABIに合わせるための変更であり、slice
のデータがCとGoの間で正しく共有されることを保証します。 -
C関数の引数型の変更:
-struct __go_string __go_byte_array_to_string(const void* p, int len); +struct __go_string __go_byte_array_to_string(const void* p, intgo len); // ... struct __go_string GoString(char *p) { - int len = (p != NULL) ? strlen(p) : 0; + intgo len = (p != NULL) ? strlen(p) : 0; return __go_byte_array_to_string(p, len); } // ... -struct __go_string GoStringN(char *p, int n) { +struct __go_string GoStringN(char *p, intgo n) { return __go_byte_array_to_string(p, n); } // ... -Slice GoBytes(char *p, int n) { +Slice GoBytes(char *p, intgo n) { struct __go_string s = { (const unsigned char *)p, n }; return __go_string_to_byte_array(s); }
__go_byte_array_to_string
,GoString
,GoStringN
,GoBytes
といった、Goのstring
やslice
の長さを扱うC関数の引数やローカル変数の型がint
からintgo
に変更されました。これにより、これらの関数がgccgo
の期待する型シグネチャと一致し、GoとCの間の相互運用性が向上します。
-
これらの変更は、cgo
が生成するCコードがgccgo
コンパイラによって正しく解釈され、コンパイルされるようにするために不可欠です。特に、Goの内部的なデータ構造(string
やslice
)のC表現における長さフィールドの型をgccgo
のABIに合わせることで、GoとCの間のデータ交換における潜在的な問題を解消しています。
関連リンク
- Go言語の
cgo
に関する公式ドキュメント: https://pkg.go.dev/cmd/cgo gccgo
プロジェクトのウェブサイト (GCCの一部): https://gcc.gnu.org/go/intptr_t
に関する情報 (C言語の標準): https://en.cppreference.com/w/c/types/integer
参考にした情報源リンク
- Go言語のソースコード (特に
src/cmd/cgo
ディレクトリ) - GCCのドキュメント (特に
gccgo
に関する部分) - C言語の標準仕様書 (特に整数型に関する部分)
- Go言語の
string
とslice
の内部表現に関する一般的な情報源(ブログ記事、Goのソースコード解説など) - このコミットのGo Gerritレビューページ: https://golang.org/cl/7057064 (コミットメッセージに記載されているリンク)
- このレビューページは、コミットの背景や議論、関連する変更を理解する上で非常に有用です。# [インデックス 14845] ファイルの概要
このコミットは、Go言語のcgo
ツールにおけるgccgo
コンパイラに関する特定の挙動を修正するものです。具体的には、src/cmd/cgo/out.go
ファイルが変更されており、cgo
が生成するCコードにおいて、_Ctype_void
の定義と、Goのslice
型やstring
型に関連する内部表現(特に長さを示すフィールド)の扱いがgccgo
の期待する形式に合わせられています。これにより、gccgo
環境下でのcgo
の互換性と正確性が向上します。
コミット
cmd/cgo
: gccgo
向けにintgo
を使用し、void
の戻り値型としてslice
を使用しないようにする。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/eee3dd1292ba1b4282b39e3288239d5259a765b4
元コミット内容
commit eee3dd1292ba1b4282b39e3288239d5259a765b4
Author: Ian Lance Taylor <iant@golang.org>
Date: Wed Jan 9 15:25:46 2013 -0800
cmd/cgo: for gccgo: use intgo, don't use slice as void return type
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7057064
変更の背景
Go言語には、公式のコンパイラであるgc
(Go Compiler)と、GCCのフロントエンドとして実装されたgccgo
の2つの主要なコンパイラがあります。cgo
はGoプログラムからC言語のコードを呼び出すためのツールであり、その過程でGoとCの間でデータ型を変換したり、Cの関数シグネチャをGoのそれにマッピングしたりします。
このコミットが行われた背景には、gc
とgccgo
の間での内部的な型表現の違いがありました。特に、以下の点が問題となっていました。
void
型の表現: C言語のvoid
型は、Go言語には直接対応する型がありません。cgo
はこれをGo側で表現するために_Ctype_void
という型を生成しますが、gc
とgccgo
ではその内部表現が異なっていました。gc
は[0]byte
(長さ0のバイト配列)として表現していましたが、gccgo
はbyte
(単一のバイト)として表現することを期待していました。この不一致が、void
型を扱う際のコンパイルエラーや予期せぬ挙動を引き起こす可能性がありました。- Goの
string
およびslice
の内部表現: Goのstring
型やslice
型は、内部的にデータへのポインタと長さを保持する構造体として表現されます。この長さを示すフィールドの型が、gc
とgccgo
で異なっていました。gc
は通常のint
を使用していましたが、gccgo
はintgo
という特定の型(通常はintptr_t
にマップされる)を期待していました。この不一致は、CコードからGoのstring
やslice
を操作する際に、不正なメモリアクセスやデータ破損につながる可能性がありました。 void
戻り値型としてのslice
の使用:cgo
の内部処理において、特定の状況でvoid
の戻り値型をSlice
(Goのslice
のC表現)として扱ってしまうケースがあったようです。これはセマンティクス的に誤りであり、gccgo
がこれを正しく処理できない可能性がありました。
これらの不一致を解消し、gccgo
環境下でもcgo
が生成するコードが正しくコンパイルされ、期待通りに動作するようにするために、この変更が導入されました。
前提知識の解説
cgo
cgo
は、Go言語のプログラムからC言語のコードを呼び出すためのツールです。Goのソースファイル内にCのコードを直接記述したり、既存のCライブラリをリンクしたりすることを可能にします。cgo
は、GoとCの間の型変換や関数呼び出しの橋渡しとなるコード(スタブコード)を自動生成します。
gcとgccgo
- gc (Go Compiler): Go言語の公式コンパイラであり、Goプロジェクトによって開発・メンテナンスされています。Goのソースコードを直接機械語にコンパイルします。
- gccgo: GCC (GNU Compiler Collection) のフロントエンドとして実装されたGoコンパイラです。GCCの最適化パスやバックエンドを利用できるため、特定のプラットフォームでのパフォーマンスや互換性において利点を持つことがあります。
gc
とは異なる内部的な型表現やABI (Application Binary Interface) を持つことがあります。
intgo
intgo
は、gccgo
コンパイラがGoのint
型やポインタのオフセット、長さなどを表現するために内部的に使用する型です。通常、C言語のintptr_t
にマップされます。intptr_t
は、ポインタを保持できる十分な大きさを持つ整数型であり、システムによって32ビットまたは64ビットになります。gc
ではこれらの用途に通常のint
が使われることが多いですが、gccgo
ではABIの互換性やポータビリティのためにintgo
が導入されています。
_Ctype_void
_Ctype_void
は、cgo
がC言語のvoid
型をGo言語側で表現するために生成する内部的な型です。Cのvoid
は「型なし」を意味し、Goには直接対応する型がありません。このコミット以前は、gc
では[0]byte
(長さ0のバイト配列)として表現されていましたが、gccgo
ではbyte
として表現されるべきでした。
Goのstringとsliceの内部表現
Goのstring
型は、読み取り専用のバイト列へのポインタと、そのバイト列の長さを保持する構造体です。
Goのslice
型は、要素へのポインタ、スライスの長さ(len
)、およびスライスの容量(cap
)を保持する構造体です。
これらの長さや容量を示すフィールドは、C言語側からアクセスされる際に、gc
とgccgo
で期待される型が異なることが問題でした。
技術的詳細
このコミットは、cgo
が生成するCコードにおいて、gc
とgccgo
の間の内部的な型表現の不一致を解消することを目的としています。
-
_Ctype_void
の条件付き定義:src/cmd/cgo/out.go
の変更により、_Ctype_void
の定義が*gccgo
フラグ(gccgo
コンパイラを使用しているかどうかを示す)に基づいて条件付きになりました。*gccgo
がtrue
の場合、_Ctype_void
はbyte
として定義されます。- それ以外の場合(
gc
を使用している場合)、_Ctype_void
は引き続き[0]byte
として定義されます。 - これにより、各コンパイラが期待する
void
型のGo表現が提供され、コンパイルエラーやランタイムエラーが回避されます。
-
intgo
の導入と使用:cPrologGccgo
というCのプロローグコード(gccgo
向けにcgo
が生成するCコードの冒頭部分)にtypedef intptr_t intgo;
が追加されました。これにより、Cコード内でintgo
がintptr_t
のエイリアスとして利用可能になります。- Goの
__go_string
構造体(Goのstring
のC表現)の__length
フィールドの型がint
からintgo
に変更されました。 - Goの
__go_open_array
構造体(Goのslice
のC表現)の__count
および__capacity
フィールドの型がint
からintgo
に変更されました。 __go_byte_array_to_string
関数のlen
引数、GoString
関数のlen
変数、GoStringN
関数のn
引数、GoBytes
関数のn
引数など、Goのstring
やslice
の長さを扱うC関数や変数でint
がintgo
に置き換えられました。- これらの変更により、
gccgo
が期待するstring
やslice
の長さフィールドの型と一致し、GoとCの間でのデータ受け渡しが正しく行われるようになります。
-
void
戻り値型としてのslice
の使用の回避:- コミットメッセージの「don't use slice as void return type」という記述は、具体的なコード変更としては
_Ctype_void
の定義変更とintgo
の使用によって間接的に解決されていると考えられます。void
型が正しくbyte
として扱われることで、誤ってSlice
として解釈されるような状況が解消されたと推測されます。
- コミットメッセージの「don't use slice as void return type」という記述は、具体的なコード変更としては
これらの変更は、cgo
が生成するCコードがgccgo
のABIとより密接に一致するようにすることで、gccgo
環境下でのGoプログラムの安定性と互換性を大幅に向上させます。
コアとなるコードの変更箇所
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -75,7 +75,11 @@ func (p *Package) writeDefs() {
conf.Fprint(fgo2, fset, def.Go)
fmt.Fprintf(fgo2, "\n\n")
}\n
- fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\\n")
+ if *gccgo {
+ fmt.Fprintf(fgo2, "type _Ctype_void byte\\n")
+ } else {
+ fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\\n")
+ }\n
\n
if *gccgo {
fmt.Fprintf(fc, cPrologGccgo)
@@ -1062,19 +1066,20 @@ const cPrologGccgo = `
#include <string.h>\n
\n
typedef unsigned char byte;\n
+typedef intptr_t intgo;\n
\n
struct __go_string {\n
const unsigned char *__data;\n
- int __length;\n
+ intgo __length;\n
};\n
\n
typedef struct __go_open_array {\n
void* __values;\n
- int __count;\n
- int __capacity;\n
+ intgo __count;\n
+ intgo __capacity;\n
} Slice;\n
\n
-struct __go_string __go_byte_array_to_string(const void* p, int len);\n
+struct __go_string __go_byte_array_to_string(const void* p, intgo len);\n
struct __go_open_array __go_string_to_byte_array (struct __go_string str);\n
\n
const char *CString(struct __go_string s) {\n
@@ -1082,15 +1087,15 @@ const char *CString(struct __go_string s) {\n
}\n
\n
struct __go_string GoString(char *p) {\n
-\tint len = (p != NULL) ? strlen(p) : 0;\n
+\tintgo len = (p != NULL) ? strlen(p) : 0;\n
return __go_byte_array_to_string(p, len);\n
}\n
\n
-struct __go_string GoStringN(char *p, int n) {\n
+struct __go_string GoStringN(char *p, intgo n) {\n
return __go_byte_array_to_string(p, n);\n
}\n
\n
-Slice GoBytes(char *p, int n) {\n
+Slice GoBytes(char *p, intgo n) {\n
struct __go_string s = { (const unsigned char *)p, n };\n
return __go_string_to_byte_array(s);\n
}\n
コアとなるコードの解説
src/cmd/cgo/out.go
の変更点
-
_Ctype_void
の定義の条件分岐:- fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\\n") + if *gccgo { + fmt.Fprintf(fgo2, "type _Ctype_void byte\\n") + } else { + fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\\n") + }
この変更は、Go側でCの
void
型を表現する_Ctype_void
の定義を、使用しているコンパイラ(gc
かgccgo
か)に応じて切り替えるものです。*gccgo
がtrue
の場合(gccgo
コンパイラを使用している場合)、_Ctype_void
はbyte
として定義されます。これはgccgo
がvoid
型を単一のバイトとして扱うことを期待しているためです。- それ以外の場合(デフォルトの
gc
コンパイラを使用している場合)、_Ctype_void
は以前と同様に[0]byte
(長さ0のバイト配列)として定義されます。これはgc
がvoid
型をこのように表現するためです。 この条件分岐により、両方のコンパイラでvoid
型の扱いが正しくなります。
-
cPrologGccgo
内のintgo
の導入と使用:cPrologGccgo
は、gccgo
向けにcgo
が生成するCコードの冒頭に挿入されるC言語のコードブロックです。-
typedef intptr_t intgo;
の追加:typedef unsigned char byte; +typedef intptr_t intgo;
intgo
という新しい型が導入され、それがC標準ライブラリのintptr_t
にtypedef
されています。intptr_t
は、ポインタを保持できる十分な大きさを持つ整数型であり、システム(32ビットまたは64ビット)に応じて適切なサイズになります。これにより、Goの内部的な長さやオフセットを表現する際に、ポインタのサイズに合わせた整数型を使用できるようになります。 -
__go_string
構造体の__length
フィールドの型変更:struct __go_string { const unsigned char *__data; - int __length; + intgo __length; };
Goの
string
型がC側で表現される__go_string
構造体の__length
フィールドの型がint
からintgo
に変更されました。これにより、gccgo
が期待するstring
の長さフィールドの型と一致し、GoとCの間でのstring
の受け渡しが正しく行われます。 -
__go_open_array
構造体の__count
と__capacity
フィールドの型変更:typedef struct __go_open_array { void* __values; - int __count; - int __capacity; + intgo __count; + intgo __capacity; } Slice;
Goの
slice
型がC側で表現される__go_open_array
構造体の__count
(長さ)と__capacity
(容量)フィールドの型がint
からintgo
に変更されました。これもgccgo
のABIに合わせるための変更であり、slice
のデータがCとGoの間で正しく共有されることを保証します。 -
C関数の引数型の変更:
-struct __go_string __go_byte_array_to_string(const void* p, int len); +struct __go_string __go_byte_array_to_string(const void* p, intgo len); // ... struct __go_string GoString(char *p) { - int len = (p != NULL) ? strlen(p) : 0; + intgo len = (p != NULL) ? strlen(p) : 0; return __go_byte_array_to_string(p, len); } // ... -struct __go_string GoStringN(char *p, int n) { +struct __go_string GoStringN(char *p, intgo n) { return __go_byte_array_to_string(p, n); } // ... -Slice GoBytes(char *p, int n) { +Slice GoBytes(char *p, intgo n) { struct __go_string s = { (const unsigned char *)p, n }; return __go_string_to_byte_array(s); }
__go_byte_array_to_string
,GoString
,GoStringN
,GoBytes
といった、Goのstring
やslice
の長さを扱うC関数の引数やローカル変数の型がint
からintgo
に変更されました。これにより、これらの関数がgccgo
の期待する型シグネチャと一致し、GoとCの間の相互運用性が向上します。
-
これらの変更は、cgo
が生成するCコードがgccgo
コンパイラによって正しく解釈され、コンパイルされるようにするために不可欠です。特に、Goの内部的なデータ構造(string
やslice
)のC表現における長さフィールドの型をgccgo
のABIに合わせることで、GoとCの間のデータ交換における潜在的な問題を解消しています。
関連リンク
- Go言語の
cgo
に関する公式ドキュメント: https://pkg.go.dev/cmd/cgo gccgo
プロジェクトのウェブサイト (GCCの一部): https://gcc.gnu.org/go/intptr_t
に関する情報 (C言語の標準): https://en.cppreference.com/w/c/types/integer
参考にした情報源リンク
- Go言語のソースコード (特に
src/cmd/cgo
ディレクトリ) - GCCのドキュメント (特に
gccgo
に関する部分) - C言語の標準仕様書 (特に整数型に関する部分)
- Go言語の
string
とslice
の内部表現に関する一般的な情報源(ブログ記事、Goのソースコード解説など) - このコミットのGo Gerritレビューページ: https://golang.org/cl/7057064 (コミットメッセージに記載されているリンク)
- このレビューページは、コミットの背景や議論、関連する変更を理解する上で非常に有用です。