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

[インデックス 14032] ファイルの概要

このコミットは、Go言語のツールチェインの一部である cmd/cc における型マッピングの変更に関するものです。具体的には、C言語の int および uint 型が、Go言語の定義においてそれぞれ int32 および uint32 に明示的にマッピングされるように修正されています。これにより、異なるアーキテクチャ間での型のサイズに関する潜在的な不整合が解消され、より堅牢なCGo連携が実現されます。

コミット

commit 16bea49ede776bd781515546e9a3df22c3dcfe06
Author: Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
Date:   Sat Oct 6 13:56:12 2012 +0800

    cmd/cc: map C int to int32 in Go defs
    
    R=golang-dev, minux.ma, rsc
    CC=golang-dev
    https://golang.org/cl/6621052

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/16bea49ede776bd781515546e9a3df22c3dcfe06

元コミット内容

cmd/cc: map C int to int32 in Go defs

変更の背景

Go言語は、C言語のコードをGoプログラムから呼び出すための cgo というメカニズムを提供しています。この cgo を利用する際、C言語の型とGo言語の型との間で適切なマッピングが行われる必要があります。

C言語の int 型は、そのサイズが処理系(コンパイラやターゲットアーキテクチャ)によって32ビットまたは64ビットと異なる場合があります。一方、Go言語の int 型も同様に、実行されるプラットフォームのアーキテクチャ(32ビットまたは64ビット)に依存してサイズが変化します。

このコミットが行われた背景には、C言語の int 型が一般的に32ビットであるという慣習と、Go言語の int 型がプラットフォーム依存であることによる潜在的な型の不整合がありました。もしC言語の int が32ビットで、Go言語の int が64ビットの環境で実行された場合、型変換時に予期せぬ挙動やデータ損失が発生する可能性がありました。

この問題を解決し、CGo連携における型の安全性を高めるために、C言語の int および uint 型をGo言語の定義において明示的に固定サイズの int32 および uint32 にマッピングする変更が導入されました。これにより、C言語の int が常に32ビットとして扱われることが保証され、異なるアーキテクチャ間での互換性が向上します。

前提知識の解説

Go言語とCGo

Go言語は、C言語のコードを直接呼び出すための cgo というツールを提供しています。これにより、既存のCライブラリをGoプログラムから利用したり、パフォーマンスが重要な部分をC言語で記述したりすることが可能になります。cgo は、C言語のソースコードをGo言語から呼び出し可能な形式に変換し、GoとCの間の型変換やメモリ管理を仲介します。

C言語の整数型

C言語の整数型、特に int は、そのサイズが標準で厳密に定義されていません。C標準では、int は少なくとも16ビット幅を持つことが保証されていますが、多くの現代的なシステムでは32ビット幅が一般的です。64ビットシステムでは、longlong long が64ビットとして使われることが多いですが、int が32ビットのままのこともあります。この可変性が、異なる環境間でのCGo連携において問題を引き起こす可能性があります。

Go言語の整数型

Go言語には、固定サイズの整数型とプラットフォーム依存の整数型があります。

  • 固定サイズ型: int8, int16, int32, int64, uint8, uint16, uint32, uint64 など。これらはそれぞれ8ビット、16ビット、32ビット、64ビットの符号付き/符号なし整数を厳密に表します。
  • プラットフォーム依存型: int, uint, uintptr。これらの型は、実行されるCPUアーキテクチャ(32ビットまたは64ビット)に応じてサイズが変化します。例えば、32ビットシステムでは int は32ビット、64ビットシステムでは64ビットになります。

cmd/cc

cmd/cc は、Go言語のツールチェインの一部であり、CGoのビルドプロセスにおいてC言語のコードをコンパイルする役割を担っています。このツールは、C言語の型をGo言語の型にどのようにマッピングするかを定義する内部ロジックを持っています。

技術的詳細

このコミットは、src/cmd/cc/godefs.c というファイル内の型定義に関するロジックを変更しています。このファイルは、C言語の型をGo言語の型に変換する際の規則を記述していると考えられます。

変更前は、C言語の TINT (int) と TUINT (unsigned int) が、Go言語の定義においてそれぞれ intuint というプラットフォーム依存の型にマッピングされていました。

// 変更前
switch(t->etype) {
case TINT:
    Bprint(&outbuf, "int"); // CのintをGoのintにマッピング
    break;
case TUINT:
    Bprint(&outbuf, "uint"); // CのuintをGoのuintにマッピング
    break;
// ...
}

このマッピングは、Go言語の int が実行環境によって32ビットまたは64ビットになりうるため、C言語の int が一般的に32ビットであるという前提と合致しない場合に問題を引き起こす可能性がありました。例えば、C言語のライブラリが32ビットの int を期待しているにもかかわらず、Goプログラムが64ビットの int として扱ってしまうと、データの切り捨てや予期せぬ値の解釈が発生する恐れがあります。

このコミットでは、このマッピングを明示的に固定サイズの型に変更しています。

// 変更後
switch(t->etype) {
case TINT:
    Bprint(&outbuf, "int32"); // CのintをGoのint32にマッピング
    break;
case TUINT:
    Bprint(&outbuf, "uint32"); // CのuintをGoのuint32にマッピング
    break;
// ...
}

これにより、C言語の int および uint は、Go言語の定義において常に32ビットの符号付き/符号なし整数として扱われることが保証されます。これは、C言語の int が多くのシステムで32ビットであるという事実と整合性が取れており、CGo連携における型の安全性を向上させます。

この変更は、cgo を利用してC言語のコードをGoから呼び出す際に、C言語の int 型がGo言語の int32 型として適切に解釈されることを保証し、異なるアーキテクチャ間での移植性や互換性の問題を軽減します。

コアとなるコードの変更箇所

変更は src/cmd/cc/godefs.c ファイルの printtypename 関数内で行われています。

--- a/src/cmd/cc/godefs.c
+++ b/src/cmd/cc/godefs.c
@@ -188,10 +188,10 @@ printtypename(Type *t)
 
  	switch(t->etype) {
  	case TINT:
- 		Bprint(&outbuf, "int");
+ 		Bprint(&outbuf, "int32");
  		break;
  	case TUINT:
- 		Bprint(&outbuf, "uint");
+ 		Bprint(&outbuf, "uint32");
  		break;
  	case TCHAR:
  		Bprint(&outbuf, "int8");

コアとなるコードの解説

printtypename 関数は、C言語の型定義をGo言語の型定義に変換し、出力バッファ (outbuf) に書き込む役割を担っています。

この関数内の switch(t->etype) 文は、入力されたC言語の型 (t->etype) に応じて、対応するGo言語の型名を決定しています。

  • case TINT:: C言語の int 型に対応します。

    • 変更前: Bprint(&outbuf, "int"); は、Go言語のプラットフォーム依存の int 型を出力していました。
    • 変更後: Bprint(&outbuf, "int32"); は、Go言語の固定サイズである int32 型を出力するように変更されました。
  • case TUINT:: C言語の unsigned int 型に対応します。

    • 変更前: Bprint(&outbuf, "uint"); は、Go言語のプラットフォーム依存の uint 型を出力していました。
    • 変更後: Bprint(&outbuf, "uint32"); は、Go言語の固定サイズである uint32 型を出力するように変更されました。

この修正により、cmd/cc がC言語の int および uint 型をGo言語の定義に変換する際に、常に32ビットの固定サイズ型を使用するようになり、CGo連携における型の厳密性と互換性が向上しました。

関連リンク

参考にした情報源リンク