C言語で暗黙的に行われる型変換についてまとめます。通常の算術型変換の言語仕様を紹介します。
通常の算術型変換(usual arithmetic conversion)
C90の言語仕様を紹介します。
まず,一方のオペランドが型long doubleをもつ場合,他方のオペランドをlong doubleに型変換する。
そうでない場合,一方のオペランドが型doubleをもつならば,他方のオペランドをdoubleに型変換する。
そうでない場合,一方のオペランドが型floatをもつならば,他方のオペランドをfloatに型変換する。
そうでない場合,次の規則に従って汎整数拡張を両オペランドに対して行う。
一方のオペランドが型unsigned long intをもつ場合,他方のオペランドをunsigned long intに型変換する。
そうでない場合,一方のオペランドが型long intをもち,他方のオペランドが型unsigned intをもち,更に,long intがunsigned intのすべての値を表現できるなら,型unsinged intのオペランドをlong intに型変換する。long intがunsigned intのすべての値を表現できるないなら,両オペランドをunsigned long intに型変換する。
そうでない場合,一方のオペランドが型long intをもつならば,他方のオペランドをlong intに型変換する。
そうでない場合,一方のオペランドが型unsigned intをもつならば,他方のオペランドをunsigned intに型変換する。
そうでない場合,両オペランドは型intをもつ。
JIS X 3010:1993 6.2.1.5
2項演算子の両辺のオブジェクトは、型が広いほうに型変換する、という処理になります。
昨日の記事から
昨日の記事で以下のプログラムを紹介しました。
#include <stdio.h>
int main(void)
{
int a = 2000000000;
int b = 2000000000;
long c = 4000000000;
printf("%ld\n", (a + b) + c);
printf("%ld\n", a + (b + c));
return 0;
}
この出力は以下でした。
3705032704
8000000000
9行目は、(a + b) + c を計算します。a と b は、型intをもつため、intで演算を行います。32ビット符号付き整数は、-2147483648~2147483647 の値を持つことが一般的です(2の補数)。このため、20億と20億を加えると、オーバーフローして負の値となります。このオーバーフローした値に変数cの値を加えているため、正しい結果となりません。
一方、10行目は、a + (b + c) を計算します。先に b + c を計算します。通常の算術型変換により、変数bの型がlong型に型変換されます。また、a + (b + c の結果)を演算する場合も、通常の算術型変換により変数bの型がlong型に型変換されます。このため、意図した値が出力されました。
最後に
(a + b) + c と a + (b + c) の計算結果が異なるのは、不思議な気がするのではないでしょうか。言語仕様を把握することにより、うまく動かなかったプログラムのメカニズムが分かりました。
C言語を使いこなしていきましょう!