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

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

このコミットは、Go言語のランタイムが依存するlib9ライブラリにおいて、-Wconversionコンパイラ警告を完全に回避するための変更を導入しています。具体的には、様々な場所で発生していた暗黙的な型変換による警告を、明示的な型キャストを追加することで解消しています。これにより、コードの堅牢性が向上し、将来的なコンパイラのバージョンアップや異なるプラットフォームでのビルドにおける潜在的な問題を未然に防ぐことを目的としています。

コミット

commit 7590e28d24d2dd50200808d2514656b6a440412f
Author: Ian Lance Taylor <iant@golang.org>
Date:   Tue Jun 25 10:44:25 2013 -0700

    lib9: avoid all -Wconversion warnings
    
    Built after adding -Wconversion to the list of compiler
    arguments used when building.  I believe these are all OK
    assuming we will not change the API.  There is no effort to
    detect overflow due to very long strings.
    
    R=golang-dev, dave, rsc, r
    CC=golang-dev
    https://golang.org/cl/10195044

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

https://github.com/golang/go/commit/7590e28d24d2dd50200808d2514656b6a440412f

元コミット内容

lib9: avoid all -Wconversion warnings

ビルド時に-Wconversionをコンパイラ引数に追加した後にビルドしました。APIを変更しない限り、これらはすべて問題ないと考えています。非常に長い文字列によるオーバーフローを検出する努力はしていません。

変更の背景

このコミットの主な背景は、Go言語のビルドプロセスに-Wconversionというコンパイラフラグが追加されたことにあります。-Wconversionは、C/C++コンパイラ(特にGCCやClang)で利用できる警告フラグの一つで、暗黙的な型変換によってデータが失われる可能性のある箇所や、意図しない動作を引き起こす可能性のある箇所を検出します。

Go言語のランタイムや標準ライブラリの一部は、C言語で書かれたlib9というライブラリに依存しています。lib9は、Plan 9オペレーティングシステムから派生したユーティリティ関数群を提供するもので、Goの低レベルなシステムコールやファイル操作、文字列処理などに利用されています。

-Wconversionフラグが導入されたことで、既存のlib9コードベースに多数の警告が発生するようになりました。これらの警告は、必ずしもバグを示すものではありませんが、コードの意図を不明瞭にしたり、将来的なコンパイラの挙動変更によって問題を引き起こす可能性を秘めています。開発チームは、コードの品質と保守性を高めるため、これらの警告を解消することを決定しました。

コミットメッセージにある「APIを変更しない限り、これらはすべて問題ない」という記述は、これらの型キャストが既存のAPIのセマンティクスを変更するものではなく、単にコンパイラの警告を抑制するためのものであることを示唆しています。また、「非常に長い文字列によるオーバーフローを検出する努力はしていません」という注意書きは、型変換によって発生しうる数値のオーバーフロー(特にstrlenの結果をintにキャストする際など)については、このコミットの範囲外であることを明記しています。これは、文字列の長さがintの最大値を超えるような極端なケースは、一般的なシステムでは発生しにくいという判断、またはその問題がこのコミットの目的ではないことを示しています。

前提知識の解説

1. lib9とは

lib9は、Go言語のプロジェクト内で使用されているC言語で書かれたライブラリ群です。その名の通り、Plan 9オペレーティングシステムに由来するユーティリティ関数やデータ構造を多く含んでいます。Go言語の初期の設計思想にはPlan 9の影響が強く見られ、特に低レベルなシステムプログラミングやファイルシステム操作において、lib9の関数が利用されていました。

Goのランタイム(ガベージコレクション、スケジューラなど)や一部の標準ライブラリ(osパッケージなど)は、直接C言語で書かれたコード(通常は_cgo_export.cのようなファイルを通じてGoコードから呼び出される)や、lib9のような外部Cライブラリに依存しています。これにより、GoはOSの低レベル機能にアクセスし、高性能な処理を実現しています。

2. -Wconversionコンパイラフラグ

-Wconversionは、GCCやClangといったC/C++コンパイラで利用できる警告オプションの一つです。このフラグを有効にすると、コンパイラは以下のような暗黙的な型変換(implicit type conversion)が発生する箇所で警告を発します。

  • 縮小変換 (Narrowing Conversion): より広い範囲の値を表現できる型から、より狭い範囲の値を表現できる型への変換。例えば、longからintへの変換、unsigned intからintへの変換など。この場合、元の値が変換先の型で表現できない範囲にあると、情報が失われる(オーバーフローやアンダーフロー)可能性があります。
  • 符号付き/符号なし変換 (Signed/Unsigned Conversion): 符号付き整数型と符号なし整数型間の変換。特に、負の符号付き整数が符号なし整数に変換されると、大きな正の値として解釈されることがあります。
  • 浮動小数点数変換 (Floating-point Conversion): 浮動小数点数型から整数型への変換。小数点以下の情報が切り捨てられます。

これらの警告は、プログラマが意図しないデータ損失や予期せぬ動作を防ぐために非常に有用です。例えば、size_t(通常は符号なし整数型で、メモリのサイズや配列のインデックスを表す)の値をint(符号付き整数型)に代入する場合、size_tの値がintの最大値を超えると、-Wconversionが警告を発します。これは、特に大規模なデータ構造を扱う際に重要になります。

このコミットでは、これらの警告を解消するために、開発者が意図的に型変換を行っていることをコンパイラに明示的に伝える「キャスト(型変換演算子)」が多用されています。例えば、(int)strlen(s)のように記述することで、strlenが返すsize_t型の値をint型に変換することを明示しています。これにより、コンパイラは警告を発しなくなります。

技術的詳細

このコミットで行われている変更は、C言語における型変換の挙動と、それに対するコンパイラの警告メカニズムの理解に基づいています。

C言語では、異なる型の値が演算や代入で組み合わされる場合、コンパイラは自動的に型変換(暗黙的な型変換)を行います。この自動変換は便利な一方で、前述の-Wconversionが警告するような、情報損失や意図しない解釈につながる可能性があります。

このコミットでは、主に以下の種類の型変換に対して明示的なキャストが追加されています。

  1. size_tからintへの変換:

    • strlen関数は文字列の長さをsize_t型で返します。size_tは通常、符号なし整数型であり、システムが扱える最大メモリサイズを表すのに十分な大きさを持っています。
    • しかし、多くのCコードでは、ループカウンタや配列のインデックスとしてint型が使われることが多く、strlenの結果をint型の変数に代入する際に暗黙的な変換が発生します。
    • 例: sz += strlen(s)+1;sz += (int)strlen(s)+1; に変更されています。これは、strlenの戻り値がint型に収まることを開発者が意図していることを示します。
    • 同様に、mallocの引数やread関数のサイズ引数など、size_tを期待する箇所にint型の値が渡される場合にもキャストが追加されています。例: malloc(sizeof(Dir)+nstr);malloc(sizeof(Dir)+(size_t)nstr); に変更されています。
  2. longtime_tからintulongへの変換:

    • st->st_mtimest->st_atimeは通常time_t型であり、これはシステムによってlonglong longなどの整数型にマップされます。
    • これらの値をulong(符号なしロング)やintに代入する際に、暗黙的な変換が発生していました。
    • 例: d->qid.vers = st->st_mtime + st->st_ctime;d->qid.vers = (ulong)(st->st_mtime + st->st_ctime); に変更されています。
    • utimes関数の引数であるtime_t型へのキャストも同様です。
  3. va_argの戻り値のキャスト:

    • 可変引数リストから値を取り出すva_argマクロは、指定された型で値を返します。しかし、引数として渡された実際の型と、va_argで指定した型が異なる場合、またはその値が別の型に代入される場合に警告が発生することがあります。
    • 例: x[0] = va_arg(f->args, int);x[0] = (char)va_arg(f->args, int);x[0] = (Rune)va_arg(f->args, int); に変更されています。これは、intとして受け取った値をcharRuneとして扱うことを明示しています。
  4. ポインタ演算の結果のキャスト:

    • ポインタの減算の結果は、通常ptrdiff_t型(符号付き整数型)になります。これをint型に代入する際に警告が発生していました。
    • 例: f->nfmt += rt - (Rune *)f->to;f->nfmt += (int)(rt - (Rune *)f->to); に変更されています。
  5. ビット演算における型の一貫性:

    • フラグのクリアなど、ビット演算を行う際に、リテラル値の型と変数の型が異なる場合に警告が発生することがあります。
    • 例: f->flags &= ~FmtSharp;f->flags &= ~(ulong)FmtSharp; に変更されています。これは、FmtSharpが定義されているマクロや定数の型が、f->flagsの型(おそらくulong)と一致しない場合に、~演算の結果が意図しない型になることを防ぐためです。

これらの変更は、コードの機能自体を変更するものではなく、コンパイラに対する「この型変換は意図的なものであり、警告は不要である」という明確な指示を与えています。これにより、コンパイラは警告を発しなくなり、ビルドログがクリーンになります。クリーンなビルドログは、本当に重要な警告(例えば、未初期化変数や潜在的なバグ)を見つけやすくするために非常に重要です。

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

このコミットは、src/lib9ディレクトリ以下の多数のCソースファイルにわたる広範な変更を含んでいます。主な変更は、様々なデータ型間の暗黙的な変換を明示的なキャストに置き換えることです。

以下に、代表的な変更箇所とそのパターンをいくつか示します。

src/lib9/_p9dir.c

--- a/src/lib9/_p9dir.c
+++ b/src/lib9/_p9dir.c
@@ -68,12 +68,12 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
 			*str += strlen(*str)+1;
 		}
 	}
-	sz += strlen(s)+1;
+	sz += (int)strlen(s)+1;
 
 	/* user */
 	snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
 	s = tmp;
-	sz += strlen(s)+1;
+	sz += (int)strlen(s)+1;
 	if(d){
 		if(*str+strlen(s)+1 > estr)
 			d->uid = "oops";
@@ -87,7 +87,7 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
 	/* group */
 	snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
 	s = tmp;
-	sz += strlen(s)+1;
+	sz += (int)strlen(s)+1;
 	if(d){
 		if(*str + strlen(s)+1 > estr)
 			d->gid = "oops";
@@ -107,10 +107,10 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
 		d->qid.vers = st->st_gen;
 #endif
 		if(d->qid.vers == 0)
-			d->qid.vers = st->st_mtime + st->st_ctime;
+			d->qid.vers = (ulong)(st->st_mtime + st->st_ctime);
 		d->mode = st->st_mode&0777;
-		d->atime = st->st_atime;
-		d->mtime = st->st_mtime;
+		d->atime = (ulong)st->st_atime;
+		d->mtime = (ulong)st->st_mtime;
 		d->length = st->st_size;
 
 		if(S_ISDIR(st->st_mode)){

src/lib9/fmt/dofmt.c

--- a/src/lib9/fmt/dofmt.c
+++ b/src/lib9/fmt/dofmt.c
@@ -25,7 +25,7 @@ int
 dofmt(Fmt *f, char *fmt)
 {
 	Rune rune, *rt, *rs;
-	int r;
+	Rune r;
 	char *t, *s;
 	int n, nfmt;
 
@@ -34,7 +34,7 @@ dofmt(Fmt *f, char *fmt)
 		if(f->runes){
 			rt = (Rune*)f->to;
 			rs = (Rune*)f->stop;
-			while((r = *(uchar*)fmt) && r != '%'){
+			while((r = (Rune)*(uchar*)fmt) && r != '%'){
 				if(r < Runeself)
 					fmt++;
 				else{
@@ -44,7 +44,7 @@ dofmt(Fmt *f, char *fmt)
 				FMTRCHAR(f, rt, rs, r);
 			}
 			fmt++;
-			f->nfmt += rt - (Rune *)f->to;
+			f->nfmt += (int)(rt - (Rune *)f->to);
 			f->to = rt;
 			if(!r)
 				return f->nfmt - nfmt;
@@ -52,7 +52,7 @@ dofmt(Fmt *f, char *fmt)
 		}else{
 			t = (char*)f->to;
 			s = (char*)f->stop;
-			while((r = *(uchar*)fmt) && r != '%'){
+			while((r = (Rune)*(uchar*)fmt) && r != '%'){
 				if(r < Runeself){
 					FMTCHAR(f, t, s, r);
 					fmt++;
@@ -70,7 +70,7 @@ dofmt(Fmt *f, char *fmt)
 				}
 			}
 			fmt++;
-			f->nfmt += t - (char *)f->to;
+			f->nfmt += (int)(t - (char *)f->to);
 			f->to = t;
 			if(!r)
 				return f->nfmt - nfmt;
@@ -87,9 +87,9 @@ void *
 __fmtflush(Fmt *f, void *t, int len)
 {
 	if(f->runes)
-		f->nfmt += (Rune*)t - (Rune*)f->to;
+		f->nfmt += (int)((Rune*)t - (Rune*)f->to);
 	else
-		f->nfmt += (char*)t - (char *)f->to;
+		f->nfmt += (int)((char*)t - (char *)f->to);
 	f->to = t;
 	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
 		f->stop = f->to;
@@ -112,7 +112,7 @@ __fmtpad(Fmt *f, int n)
 	s = (char*)f->stop;
 	for(i = 0; i < n; i++)
 		FMTCHAR(f, t, s, ' ');
-	f->nfmt += t - (char *)f->to;
+	f->nfmt += (int)(t - (char *)f->to);
 	f->to = t;
 	return 0;
 }
@@ -127,7 +127,7 @@ __rfmtpad(Fmt *f, int n)
 	s = (Rune*)f->stop;
 	for(i = 0; i < n; i++)
 		FMTRCHAR(f, t, s, ' ');
-	f->nfmt += t - (Rune *)f->to;
+	f->nfmt += (int)(t - (Rune *)f->to);
 	f->to = t;
 	return 0;
 }
@@ -157,13 +157,13 @@ __fmtcpy(Fmt *f, const void *vm, int n, int sz)
 			r = *(uchar*)m;
 			if(r < Runeself)
 				m++;
-			else if((me - m) >= UTFmax || fullrune(m, me-m))
+			else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
 				m += chartorune(&r, m);
 			else
 				break;
 			FMTRCHAR(f, rt, rs, r);
 		}
-		f->nfmt += rt - (Rune *)f->to;
+		f->nfmt += (int)(rt - (Rune *)f->to);
 		f->to = rt;
 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
 			return -1;
@@ -176,13 +176,13 @@ __fmtcpy(Fmt *f, const void *vm, int n, int sz)
 			r = *(uchar*)m;
 			if(r < Runeself)
 				m++;
-			else if((me - m) >= UTFmax || fullrune(m, me-m))
+			else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
 				m += chartorune(&r, m);
 			else
 				break;
 			FMTRUNE(f, t, s, r);
 		}
-		f->nfmt += t - (char *)f->to;
+		f->nfmt += (int)(t - (char *)f->to);
 		f->to = t;
 		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
 			return -1;
@@ -212,7 +212,7 @@ __fmtrcpy(Fmt *f, const void *vm, int n)
 		rs = (Rune*)f->stop;
 		for(me = m + n; m < me; m++)
 			FMTRCHAR(f, rt, rs, *m);
-		f->nfmt += rt - (Rune *)f->to;
+		f->nfmt += (int)(rt - (Rune *)f->to);
 		f->to = rt;
 		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
 			return -1;
@@ -225,7 +225,7 @@ __fmtrcpy(Fmt *f, const void *vm, int n)
 		r = *m;
 		FMTRUNE(f, t, s, r);
 	}
-	f->nfmt += t - (char *)f->to;
+	f->nfmt += (int)(t - (char *)f->to);
 	f->to = t;
 	if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
 		return -1;
@@ -239,7 +239,7 @@ __charfmt(Fmt *f)
 {
 	char x[1];
 
-	x[0] = va_arg(f->args, int);
+	x[0] = (char)va_arg(f->args, int);
 	f->prec = 1;
 	return __fmtcpy(f, (const char*)x, 1, 1);
 }
@@ -250,7 +250,7 @@ __runefmt(Fmt *f)
 {
 	Rune x[1];
 
-	x[0] = va_arg(f->args, int);
+	x[0] = (Rune)va_arg(f->args, int);
 	return __fmtrcpy(f, (const void*)x, 1);
 }
 
@@ -278,7 +278,7 @@ fmtstrcpy(Fmt *f, char *s)
 #endif
 		return __fmtcpy(f, s, j, i);
 	}
-	return __fmtcpy(f, s, utflen(s), strlen(s));
+	return __fmtcpy(f, s, utflen(s), (int)strlen(s));
 }
 
 /* fmt out a null terminated utf string */
@@ -309,7 +309,7 @@ fmtrunestrcpy(Fmt *f, Rune *s)
 	}else{
 		for(e = s; *e; e++)
 			;
-		n = e - s;
+		n = (int)(e - s);
 	}
 	return __fmtrcpy(f, s, n);
 }
@@ -342,8 +342,8 @@ __ifmt(Fmt *f)
 	char buf[140], *p, *conv;
 	/* 140: for 64 bits of binary + 3-byte sep every 4 digits */
 	uvlong vu;
-	ulong u;
-	int neg, base, i, n, fl, w, isv;
+	ulong fl, u;
+	int neg, base, i, n, w, isv;
 	int ndig, len, excess, bytelen;
 	char *grouping;
 	char *thousands;
@@ -377,27 +377,27 @@ __ifmt(Fmt *f)
 		if(fl & FmtUnsigned)
 			vu = va_arg(f->args, uvlong);
 		else
-			vu = va_arg(f->args, vlong);
+			vu = (uvlong)va_arg(f->args, vlong);
 	}else if(fl & FmtLong){
 		if(fl & FmtUnsigned)
 			u = va_arg(f->args, ulong);
 		else
-			u = va_arg(f->args, long);
+			u = (ulong)va_arg(f->args, long);
 	}else if(fl & FmtByte){
 		if(fl & FmtUnsigned)
 			u = (uchar)va_arg(f->args, int);
 		else
-			u = (char)va_arg(f->args, int);
+			u = (uchar)(char)va_arg(f->args, int);
 	}else if(fl & FmtShort){
 		if(fl & FmtUnsigned)
 			u = (ushort)va_arg(f->args, int);
 		else
-			u = (short)va_arg(f->args, int);
+			u = (ushort)(short)va_arg(f->args, int);
 	}else{
 		if(fl & FmtUnsigned)
 			u = va_arg(f->args, uint);
 		else
-			u = va_arg(f->args, int);
+			u = (uint)va_arg(f->args, int);
 	}
 	conv = "0123456789abcdef";
 	grouping = "\4";	/* for hex, octal etc. (undefined by spec but nice) */
@@ -428,10 +428,10 @@ __ifmt(Fmt *f)
 	}
 	if(!(fl & FmtUnsigned)){
 		if(isv && (vlong)vu < 0){
-			vu = -(vlong)vu;
+			vu = (uvlong)-(vlong)vu;
 			neg = 1;
 		}else if(!isv && (long)u < 0){
-			u = -(long)u;
+			u = (ulong)-(long)u;
 			neg = 1;
 		}
 	}
@@ -440,11 +440,11 @@ __ifmt(Fmt *f)
 	excess = 0;	/* number of bytes > number runes */
 	ndig = 0;
 	len = utflen(thousands);
-	bytelen = strlen(thousands);
+	bytelen = (int)strlen(thousands);
 	if(isv){
 		while(vu){
-			i = vu % base;
-			vu /= base;
+			i = (int)(vu % (uvlong)base);
+			vu /= (uvlong)base;
 			if((fl & FmtComma) && n % 4 == 3){
 				*p-- = ',';
 				n++;
@@ -453,15 +453,15 @@ __ifmt(Fmt *f)
 				n += len;
 				excess += bytelen - len;
 				p -= bytelen;
-				memmove(p+1, thousands, bytelen);
+				memmove(p+1, thousands, (size_t)bytelen);
 			}
 			*p-- = conv[i];
 			n++;
 		}
 	}else{
 		while(u){
-			i = u % base;
-			u /= base;
+			i = (int)(u % (ulong)base);
+			u /= (ulong)base;
 			if((fl & FmtComma) && n % 4 == 3){
 				*p-- = ',';
 				n++;
@@ -470,7 +470,7 @@ __ifmt(Fmt *f)
 				n += len;
 				excess += bytelen - len;
 				p -= bytelen;
-				memmove(p+1, thousands, bytelen);
+				memmove(p+1, thousands, (size_t)bytelen);
 			}
 			*p-- = conv[i];
 			n++;
@@ -496,14 +496,14 @@ __ifmt(Fmt *f)
 		 * Zero values don't get 0x.
 		 */
 		if(f->r == 'x' || f->r == 'X')
-			fl &= ~FmtSharp;
+			fl &= ~(ulong)FmtSharp;
 	}
 	for(w = f->prec; n < w && p > buf+3; n++){
 		if((fl & FmtApost) && __needsep(&ndig, &grouping)){
 			n += len;
 			excess += bytelen - len;
 			p -= bytelen;
-			memmove(p+1, thousands, bytelen);
+			memmove(p+1, thousands, (size_t)bytelen);
 		}
 		*p-- = '0';
 	}
@@ -514,7 +514,7 @@ __ifmt(Fmt *f)
 		n += 2;
 	else if(base == 8){
 		if(p[1] == '0')
-			fl &= ~FmtSharp;
+			fl &= ~(ulong)FmtSharp;
 		else
 			n++;
 	}
@@ -528,15 +528,15 @@ __ifmt(Fmt *f)
 			n += len;
 			excess += bytelen - len;
 			p -= bytelen;
-			memmove(p+1, thousands, bytelen);
+			memmove(p+1, thousands, (size_t)bytelen);
 		}
 		*p-- = '0';
 	}
-	f->flags &= ~FmtWidth;
+	f->flags &= ~(ulong)FmtWidth;
 	if(fl & FmtSharp){
 		if(base == 16)
-			*p-- = f->r;
+			*p-- = (char)f->r;
 		if(base == 16 || base == 8)
 			*p-- = '0';
 	}
@@ -546,7 +546,7 @@ __ifmt(Fmt *f)
 		*p-- = '+';
 	else if(fl & FmtSpace)
 		*p-- = ' ';
-	f->flags &= ~FmtPrec;
+	f->flags &= ~(ulong)FmtPrec;
 	return __fmtcpy(f, p + 1, n, n + excess);
 }
 
@@ -563,9 +563,9 @@ __countfmt(Fmt *f)
 	}else if(fl & FmtLong){
 		*(long*)p = f->nfmt;
 	}else if(fl & FmtByte){
-		*(char*)p = f->nfmt;
+		*(char*)p = (char)f->nfmt;
 	}else if(fl & FmtShort){
-		*(short*)p = f->nfmt;
+		*(short*)p = (short)f->nfmt;
 	}else{
 		*(int*)p = f->nfmt;
 	}\n

コアとなるコードの解説

上記のコード変更は、C言語の型システムにおける暗黙的な型変換によって発生する-Wconversion警告を解消するためのものです。それぞれの変更は、特定のコンテキストで発生する型ミスマッチを明示的に解決しています。

_p9dir.c の変更

  • strlen(s) の結果のキャスト: strlensize_t型(通常は符号なし整数)を返しますが、sz変数がint型であるため、sz += strlen(s)+1; のような式で暗黙的な縮小変換が発生していました。(int)strlen(s)と明示的にキャストすることで、strlenの結果をintとして扱うことをコンパイラに伝えています。これは、文字列の長さがintの最大値を超えることは稀であるという前提に基づいています。
  • st_mtime, st_ctime, st_atime のキャスト: struct statのタイムスタンプフィールド(st_mtime, st_ctime, st_atime)はtime_t型であり、これはシステムによって異なる整数型にマップされます。d->qid.vers, d->atime, d->mtimeといったフィールドがulong型であるため、これらの代入時に暗黙的な変換が発生していました。(ulong)へのキャストは、これらのタイムスタンプ値を符号なしロング整数として扱うことを明示しています。

fmt/dofmt.c の変更

  • Rune r;int r; の変更: dofmt関数内で、文字を処理するための変数rの型がintからRuneに変更されています。RuneはGo言語におけるUnicodeコードポイントを表す型であり、C言語の文脈では通常longintのエイリアスとして定義されます。この変更は、文字コードをより正確に表現するため、および関連するキャストの必要性を生み出すために行われています。
  • *(uchar*)fmt のキャスト: while((r = *(uchar*)fmt) && r != '%') のようなループで、char*uchar*にキャストして文字を読み込み、それをRune型の変数rに代入しています。この際、*(uchar*)fmtの結果がintに昇格され、その後Runeに暗黙的に変換されることで警告が発生していました。(Rune)*(uchar*)fmtとすることで、この変換を明示しています。
  • ポインタ減算の結果のキャスト: f->nfmt += rt - (Rune *)f->to; のような式では、ポインタの減算の結果(ptrdiff_t型)がf->nfmt(おそらくint型)に代入される際に暗黙的な変換が発生していました。(int)へのキャストは、この変換を意図的なものとしています。
  • va_arg の戻り値のキャスト: __charfmt__runefmt関数で、va_argから取得したint型の値をcharRune型の配列要素に代入する際に警告が発生していました。(char)va_arg(f->args, int)(Rune)va_arg(f->args, int)とすることで、この縮小変換を明示しています。
  • strlen の結果のキャスト: fmtstrcpy関数で、utflen(s)strlen(s)の結果を__fmtcpyに渡す際に、strlen(s)の結果がintにキャストされています。
  • 数値フォーマット関数の引数キャスト: __ifmt関数では、va_argから取得した様々な整数型(vlong, long, intなど)の値を、uvlongulong, uchar, ushort, uintといった符号なし型に代入する際に、明示的なキャストが追加されています。これは、符号付き/符号なし間の変換警告を解消するためです。
  • ビット演算における型の一貫性: fl &= ~FmtSharp; のようなビット演算では、~FmtSharpの結果の型がflの型(ulong)と異なる場合に警告が発生していました。fl &= ~(ulong)FmtSharp; とすることで、~演算の結果をulongとして扱うことを明示し、型の一貫性を保っています。

これらの変更は、コードの動作を変更することなく、コンパイラの警告を抑制し、コードの意図をより明確にするための「クリーンアップ」作業です。これにより、開発者は本当に重要な警告に集中できるようになります。

関連リンク

参考にした情報源リンク

  • GCCの警告オプションに関するドキュメント: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html (特に-Wconversionのセクション)
  • C言語の型変換に関する一般的な情報源 (例: C Standard Library documentation, C programming tutorials)
  • Go言語の内部構造に関するブログ記事やドキュメント (例: Go runtime source code analysis)
  • Plan 9の歴史と影響に関する情報源 (例: Wikipedia, academic papers)