[インデックス 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 (コミットメッセージに記載されているリンク)
- このレビューページは、コミットの背景や議論、関連する変更を理解する上で非常に有用です。