|
符号付きと符号なし
今回は、符号付き(signed)と符号なし(unsigned)のデータ型についてです。ここは、思わぬ落とし穴になりがちなところです。では、次のサンプルプログラムを見てください。
#include <stdio.h>
int main(int argc, char *argv[])
{
long lv = -10000;
unsigned long ulv = 10000;
if (lv >= ulv)
{
printf("long value is greater.\n");
}
else
{
printf("unsigned long value is greater.\n");
}
return 0;
} |
long型とunsigned long型の変数を比較しているだけですが、この結果がどうなるかわかりますか?このプログラムを実行すると、なんと"long value is greater."が出力されます。マイナスの値とプラスの値を比較したのに、マイナスのほうが大きいという結果になってしまいます。なぜでしょうか。
その理由は、long型とunsigned long型を比較するときは、long型の変数がunsigned long型に変換されるからです。-10000をunsigned long型に変換すると、4294957296になります。当然こちらのほうが大きいです。このような演算時の型変換は"算術変換"と呼ばれます。
算術変換は、このほかにも浮動小数点数についても実行されますが、特にここでは取り上げません。大切なことは、signedとunsignedでは、unsignedの方が上位になるということです。従って、変数にマイナスの値が入っていると、とんでもなく大きいプラスの値になってしまうことがあるということです。
ちなみに、VCでこのような比較をしようとすると、
warning C4018: '>=' : signed と unsigned の数値を比較しようとしました。 |
という警告が出ます。また、gcc -Wallでは警告は出ないようです。
プログラムを書くときには、long型とunsigned long型の比較はしないようにしましょう。もともとlong型とunsigned long型は用途が違います。用途の違う変数同士を比較しないといけなくなったとしたら、どこか設計がおかしいんじゃないか?と疑ったほうがいいでしょう。
上のサンプルのように、あからさまに書いてあればまだわかりやすいですが、では、次のような場合はどうでしょうか。
#include <stdio.h>
#include <time.h>
int main(int argc, char *argv[])
{
time_t tv = -10000;
long lv = 10000;
if (tv >= lv)
{
printf("time value is greater.\n");
}
else
{
printf("long value is greater.\n");
}
return 0;
}
|
time_tというのは時刻を保持するのに使われるデータ型ですね。でもここでちょっと考えてしまいませんか?time_tが果たしてunsigned longなのかsigned longなのか、それによって結果が変わってくることはもうわかりますよね。
こんな風に、typedefされているデータ型なんかを使うときは、気をつけていないとうっかり他のデータ型と比較して、思わぬバグを生む原因になります。
ちなみに答えを言うと、上のプログラムは"long value is greater."が出力されます。time_tはlong型です。
では、次のサンプルプログラムを見てください。
#include <stdio.h>
int main(int argc, char *argv[])
{
short sv = -10000;
unsigned short usv = 10000;
if (sv >= usv)
{
printf("short value is greater.\n");
}
else
{
printf("unsigned short value is greater.\n");
}
return 0;
}
|
今度はshort型とunsigned short型を比較しています。この場合はどうなるでしょうか。このプログラムを実行すると、実は"unsigned short value is greater."が出力されます。long型の時とは結果が違ってきます。これはどういうことでしょうか。
その理由は、演算(この場合は比較演算)が実行される前に、short型はint型に型変換されるからです。(ここではint型を4バイトとしています。)。short型もunsigned short型もint型に変換されるので、int型同士の比較となり、usvのほうが大きくなります。
このような型変換は、本によっては"単項変換"と書かれています。これは算術変換より前に実行されます。int型より小さいデータ型は、演算前にint型に変換されます。
|