[インデックス 12585] ファイルの概要
このコミットは、Go言語の公式ドキュメントに「C? Go? Cgo!」というタイトルの記事を追加するものです。この記事は、GoプログラムからC言語のコードを呼び出すためのGoの機能であるcgo
について解説しています。具体的には、cgo
の基本的な使い方、GoとCの型変換、文字列の扱い、メモリ管理、そしてcgo
パッケージのビルド方法について、具体的なコード例を交えながら説明しています。
コミット
commit 60b98d62087d582dafdda68c2af281c5e204fe03
Author: Francisco Souza <franciscossouza@gmail.com>
Date: Tue Mar 13 09:07:37 2012 +1100
doc: add C? Go? Cgo! article
Originally published on The Go Programming Language Blog, March 17, 2011.
http://blog.golang.org/2011/03/c-go-cgo.html
Update #2547.
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5777054
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/60b98d62087d582dafdda68c2af281c5e204fe03
元コミット内容
このコミットは、Go言語のドキュメントにcgo
に関する新しい記事「C? Go? Cgo!」を追加します。この記事は元々2011年3月17日にGoプログラミング言語の公式ブログで公開されたもので、その内容をGoの公式ドキュメントサイトに統合するものです。
変更の概要は以下の通りです。
doc/articles/c_go_cgo.html
として新しいHTMLファイルが追加され、記事の本文が含まれています。doc/docs.html
とdoc/reference.html
が更新され、新しい記事へのリンクが追加されました。cgo
の動作を示すためのGoのサンプルプログラム(cgo1.go
、cgo2.go
、cgo3.go
、cgo4.go
)がdoc/progs/
ディレクトリに追加されました。doc/progs/run
スクリプトが更新され、これらの新しいサンプルプログラムがビルドプロセスに含まれるようになりました。src/cmd/cgo/doc.go
内のcgo
ドキュメントへのリンクが、ブログ記事から新しいドキュメントサイトのパスに変更されました。
変更の背景
このコミットの主な背景は、Go言語のcgo
機能に関する重要な情報源であるブログ記事を、Goの公式ドキュメントサイトに直接統合することです。これにより、ユーザーはcgo
に関する情報をより簡単に見つけ、アクセスできるようになります。
Go言語は、システムプログラミング言語としての側面も持ち、既存のC言語ライブラリとの連携がしばしば必要とされます。cgo
はそのための公式なメカニズムであり、GoプログラムからC関数を呼び出したり、Cのデータ構造を扱ったりすることを可能にします。しかし、cgo
の利用にはGoとCの間のインターフェースの理解、メモリ管理の注意点など、特有の知識が必要です。
このブログ記事は、cgo
の基本的な概念と実践的な使用方法を分かりやすく解説しており、多くのGo開発者にとって貴重なリソースでした。このコミットによって、その貴重なコンテンツがGoの公式ドキュメントの一部となり、Goの学習者や開発者がcgo
について学ぶ際の障壁が低減されることが期待されます。また、ドキュメントの一元化は、情報の発見可能性と保守性の向上にも寄与します。
前提知識の解説
このコミットの内容を理解するためには、以下の前提知識があると役立ちます。
- Go言語の基本: Go言語の基本的な構文、パッケージシステム、関数、型、エラーハンドリング(特に
defer
文)に関する知識が必要です。 - C言語の基本: C言語の基本的な構文、関数、ポインタ、文字列(ヌル終端文字列)、標準ライブラリ(
stdlib.h
、stdio.h
など)に関する知識が必要です。特に、C言語におけるメモリ管理(malloc
とfree
)の概念は重要です。 cgo
の役割:cgo
は、GoプログラムとC言語のコードを連携させるためのGoのツールです。Goのソースファイル内に特別なコメントブロックとimport "C"
ステートメントを記述することで、Cの関数をGoから呼び出したり、Goの関数をCから呼び出したりすることが可能になります。- Goのビルドシステム:
go build
やgo install
コマンドがどのようにGoのソースコードをコンパイルし、実行可能ファイルを生成するかについての基本的な理解があると良いでしょう。cgo
を使用するファイルは、これらのコマンドによって自動的にcgo
ツールが呼び出され、GoとCのコードが適切にリンクされます。 - ポインタと
unsafe.Pointer
: Go言語は通常、ポインタ演算を制限していますが、unsafe
パッケージのunsafe.Pointer
型を使用することで、任意の型のポインタを表現し、ポインタ演算を行うことが可能になります。cgo
では、GoとCの間でメモリを共有する際にunsafe.Pointer
が頻繁に利用されます。 - Goのドキュメント構造: Goの公式ドキュメントは、
doc/articles/
ディレクトリに記事が、doc/progs/
ディレクトリに記事内で参照されるサンプルプログラムが配置されるという慣習があります。このコミットは、この慣習に従って新しい記事とサンプルプログラムを追加しています。
技術的詳細
このコミットで追加される「C? Go? Cgo!」記事は、cgo
の技術的な側面を以下の点で詳細に解説しています。
-
import "C"
疑似パッケージ:cgo
を使用するGoのソースファイルでは、import "C"
という特殊なインポート文を記述します。- この
C
は実際のGoパッケージではなく、cgo
ツールによってC言語の名前空間への参照として解釈される「疑似パッケージ」です。 - GoコードからCの関数や変数にアクセスする際は、
C.functionName
やC.variableName
のようにC
プレフィックスを使用します。
-
Cヘッダーの埋め込み:
import "C"
の直前のコメントブロック(/* ... */
)内にC言語のコードを記述できます。- このブロックは、Cコンパイラに渡されるヘッダーとして扱われます。通常、
#include
ディレクティブを使用して必要なC標準ライブラリやカスタムヘッダーを含めます。 - このコメントブロックと
import "C"
の間には、空行を挟むことはできません。
-
GoとCの型変換:
- GoとCの間でデータをやり取りする際には、明示的な型変換が必要です。
cgo
は、Cのプリミティブ型に対応するGoの型を提供します(例:C.long
,C.uint
)。- Goの型からCの型へ、またはその逆への変換は、通常のGoの型変換構文(例:
int(C.random())
,C.uint(i)
) を使用して行います。 - 特に、Cの
long
型はGoのint
型に直接変換できますが、記事では一時変数を使った明示的な変換例も示し、理解を深めています。
-
文字列の扱い:
- C言語にはGoのような組み込みの文字列型がなく、ヌル終端文字配列として表現されます。
cgo
は、Goのstring
型とCのchar*
型を相互に変換するためのヘルパー関数を提供します:C.CString(s string)
: Goの文字列をCのヌル終端文字列に変換し、Cのヒープにメモリを割り当てます。C.GoString(cs *C.char)
: Cのヌル終端文字列をGoの文字列に変換します。C.GoStringN(cs *C.char, length C.int)
: 指定された長さのCの文字列をGoの文字列に変換します。
- これらの変換はデータのコピーを伴います。
-
メモリ管理の注意点:
C.CString
などのcgo
関数によってCのヒープに割り当てられたメモリは、Goのガベージコレクタの管理外です。- したがって、Cのヒープに割り当てられたメモリは、Goコードから明示的に
C.free(unsafe.Pointer(ptr))
を呼び出して解放する必要があります。 - 記事では、
defer
文を使用してC.free
を遅延実行するイディオムを紹介しており、これによりメモリリークを防ぎつつコードの可読性を保つ方法を示しています。defer
は関数の終了時に必ず実行されるため、エラーパスでもメモリが解放されることを保証します。
-
ビルドプロセス:
cgo
を使用するGoパッケージは、通常のgo build
やgo install
コマンドでビルドできます。go
ツールはimport "C"
を認識し、自動的にcgo
ツールを呼び出して、GoとCのコードをコンパイルし、リンクします。
これらの技術的詳細は、GoとCの間のインターフェースを効果的に利用し、潜在的な問題を回避するために不可欠な知識です。
コアとなるコードの変更箇所
このコミットのコアとなる変更は、新しい記事ファイルとそれに関連するサンプルプログラムの追加、そして既存のドキュメントからのリンク更新です。
-
doc/articles/c_go_cgo.html
(新規追加):- このファイルが、
cgo
に関する記事の本文を含んでいます。HTML形式で記述されており、Goのドキュメントサイトのテンプレートシステムと互換性があります。 - 記事内では、
{{code "/doc/progs/cgo1.go" ...}}
のようなGoのドキュメントシステム特有の構文が使用されており、これにより外部のGoコード例を記事内に埋め込んで表示しています。
- このファイルが、
-
doc/progs/cgo1.go
,doc/progs/cgo2.go
,doc/progs/cgo3.go
,doc/progs/cgo4.go
(新規追加):- これらは、記事内で
cgo
の機能(C関数の呼び出し、型変換、文字列処理、メモリ管理)を実演するためのGoのサンプルプログラムです。 - 各ファイルは、
import "C"
とCのヘッダーを埋め込むコメントブロックを含んでいます。
- これらは、記事内で
-
doc/docs.html
およびdoc/reference.html
(変更):- これらのファイルは、Goのドキュメントサイトの主要なインデックスページです。
- 新しい記事
doc/articles/c_go_cgo.html
へのリンクが追加され、ユーザーが記事を発見しやすくなりました。
-
doc/progs/run
(変更):- このシェルスクリプトは、
doc/progs
ディレクトリ内のGoのサンプルプログラムをビルドおよびテストするために使用されます。 - 新しく追加された
cgo
のサンプルプログラム(cgo1
、cgo2
、cgo3
、cgo4
)がall
変数に追加され、スクリプト実行時にこれらのプログラムもビルドされるようになりました。
- このシェルスクリプトは、
-
src/cmd/cgo/doc.go
(変更):cgo
コマンド自体のドキュメントファイルです。- 以前はブログ記事へのリンク(
http://blog.golang.org/2011/03/c-go-cgo.html
)が記載されていましたが、このコミットにより、新しく追加された公式ドキュメント内の記事へのパス(http://golang.org/doc/articles/c_go_cgo.html
)に更新されました。これにより、ドキュメントの一貫性が保たれます。
これらの変更は、Goのドキュメントエコシステムにcgo
に関する包括的なリソースを統合し、ユーザーエクスペリエンスを向上させることを目的としています。
コアとなるコードの解説
ここでは、追加されたサンプルプログラムの中から、cgo
の主要な概念を示すcgo1.go
とcgo3.go
のコードを解説します。
doc/progs/cgo1.go
の解説
このファイルは、C標準ライブラリのrandom()
とsrandom()
関数をGoから呼び出す方法を示しています。
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rand
// INCLUDE OMIT
/*
#include <stdlib.h>
*/
import "C"
// STOP OMIT
func Random() int {
return int(C.random())
}
// STOP OMIT
func Seed(i int) {
C.srandom(C.uint(i))
}
// END OMIT
package rand
: このファイルがrand
パッケージの一部であることを示します。/* #include <stdlib.h> */
: このコメントブロックは、Cコンパイラに渡されるCコードです。ここでは、random()
とsrandom()
関数が定義されているC標準ライブラリのstdlib.h
をインクルードしています。このブロックはimport "C"
の直前に、空行なしで記述する必要があります。import "C"
:cgo
を使用することを示す特別なインポート文です。これにより、Goコード内でC
疑似パッケージを通じてCの関数や型にアクセスできるようになります。func Random() int
:C.random()
: Cのrandom()
関数を呼び出しています。C
プレフィックスがCの名前空間へのアクセスを示します。C.random()
はCのlong
型を返しますが、Goのint
型に変換するためにint()
でキャストしています。
func Seed(i int)
:C.srandom(C.uint(i))
: Cのsrandom()
関数を呼び出しています。srandom()
はCのunsigned int
型の引数を期待するため、Goのint
型の引数i
をC.uint(i)
としてCのunsigned int
型に変換しています。
この例は、GoからCの関数を呼び出し、GoとCの間でプリミティブ型を変換する基本的なパターンを示しています。
doc/progs/cgo3.go
の解説
このファイルは、Goの文字列をCの文字列に変換し、Cのfputs()
関数を使って標準出力に書き込む方法、そしてCで割り当てられたメモリを解放する方法を示しています。
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package print
// #include <stdio.h>
// #include <stdlib.h>
import "C"
import "unsafe"
func Print(s string) {
cs := C.CString(s)
C.fputs(cs, (*C.FILE)(C.stdout))
C.free(unsafe.Pointer(cs))
}
// END OMIT
package print
: このファイルがprint
パッケージの一部であることを示します。#include <stdio.h>
と#include <stdlib.h>
: Cのfputs()
関数が定義されているstdio.h
と、C.CString
が内部的に使用するメモリ割り当て(malloc
)とC.free
が定義されているstdlib.h
をインクルードしています。import "unsafe"
:C.free
に渡すために、Cのポインタをunsafe.Pointer
に変換する必要があるため、unsafe
パッケージをインポートしています。func Print(s string)
:cs := C.CString(s)
: Goのstring
型の引数s
を、Cのヌル終端文字列(*C.char
)に変換します。この関数はCのヒープに新しいメモリを割り当て、Goの文字列の内容をコピーします。C.fputs(cs, (*C.FILE)(C.stdout))
: Cのfputs()
関数を呼び出し、変換されたC文字列cs
を標準出力(C.stdout
)に書き込みます。C.stdout
はCのFILE*
型ですが、Go側では*C.FILE
として扱われます。C.free(unsafe.Pointer(cs))
: 非常に重要です。C.CString
によってCのヒープに割り当てられたメモリは、Goのガベージコレクタの管理外です。そのため、使用後は明示的にC.free()
を呼び出してメモリを解放する必要があります。C.free
はvoid*
型の引数を取るため、*C.char
型のcs
をunsafe.Pointer
にキャストして渡しています。
この例は、GoとCの間で文字列を安全にやり取りし、Cで割り当てられたリソースを適切に管理する方法を示しています。特に、C.free
の呼び出しを忘れるとメモリリークにつながるため、このパターンはcgo
プログラミングにおいて非常に重要です。記事では、このC.free
の呼び出しをdefer
文で囲むことで、より堅牢なコードを書く方法もcgo4.go
で示しています。
関連リンク
- Go言語公式ブログの元記事: http://blog.golang.org/2011/03/c-go-cgo.html
cgo
コマンドのドキュメント: https://golang.org/cmd/cgo/unsafe
パッケージのドキュメント: https://golang.org/pkg/unsafe/- Goの
defer
、panic
、recover
に関する記事: https://golang.org/doc/articles/defer_panic_recover.html (記事内でdefer
のイディオムを説明する際に参照されています) - Russ Cox氏の
gosqlite
プロジェクト: http://code.google.com/p/gosqlite/source/browse/sqlite/sqlite.go (cgo
ベースのパッケージのシンプルな例として記事で紹介されています) - Go Project Dashboardの
cgo
タグ付きプロジェクト: https://godashboard.appspot.com/project?tag=cgo (記事で他のcgo
パッケージの例として紹介されています) - Goランタイムの
cgocall.c
ソースコード: https://golang.org/src/pkg/runtime/cgocall.c (cgo
の内部動作に興味がある場合に参照するよう記事で示されています)
参考にした情報源リンク
- コミット情報:
./commit_data/12585.txt
- GitHubコミットページ: https://github.com/golang/go/commit/60b98d62087d582dafdda68c2af281c5e204fe03
- Go言語公式ブログ: https://blog.golang.org/
- Go言語公式ドキュメント: https://golang.org/doc/
cgo
に関する一般的な情報源 (Web検索結果に基づく)