型変換 解答ページ | Programming Place Plus C言語編 第21章

トップページC言語編第21章

問題①

問題① 次の3つの if文の中から、結果が真になるものを選んでください(何個あるかは不明)。

short snum = -10;
long lnum = -10;

if (snum == lnum) {}
if (snum == (short)lnum) {}
if ((unsigned short)snum == -10) {}


1つ目の if文は、short型と long型の比較です。型が異なる演算なので、通常の算術型変換が行われ、両オペランドともに long型に変換されます。short型の値は、long型でそのまま表現できますから、-10 のまま比較され、結果は真になります。

2つ目の if文は、long型を short型にキャストしてから比較を行っていますから、これは short型同士の比較になります。変数lnum のもともとの値である -10 は、short型に変換しても変わらず表現できますから値もそのまま保たれます。short型のランクは int型よりも低いため、整数拡張によって int型に拡張されます。ここでも特に情報を失うことはないので、-10 のまま比較され、結果は真になります。

3つ目の if文は非常にややこしいです。大抵の環境では偽になるはずですが、真になる可能性もあるかもしれません。まず、short型の -10 を unsigned short型にキャストしています。この結果、unsigned short型で表現できる最大に近い正の数になってしまうはずです。

比較は、unsigned short型と int型で行おうとしていますが、unsigned short型は int型よりもランクが低いため、整数拡張で変換されます。ここの変換結果が厄介で、int型の方が short型よりも大きい環境(現代では恐らくこれが大半でしょう)では、int型に変換されます。しかし、int型と short型の大きさが同じ環境では、unsigned int型に変換されるはずです。いずれにしても巨大な正の数はそのままの値を保ちます。

int型に変換された場合は、int 対 int の比較になるため、巨大な正の数と -10 を比較して偽になります。unsigned int型に変換された場合、通常の算術型変換により、unsigned int 対 unsigned int の比較になります。この場合、-10 の方も巨大な正の数に化けてしまいます。すると両者とも、unsigned int型で表現された巨大な同一の正の数になりますから、真になります。

一応、次のように適当なプログラムを書いて試しておきましょう。

#include <stdio.h>

int main(void)
{
    short snum = -10;
    long lnum = -10;

    if (snum == lnum) {
        puts("1");
    }
    if (snum == (short)lnum) {
        puts("2");
    }
    if ((unsigned short)snum == -10) {
        puts("3");
    }
}

実行結果:

1
2

問題②

問題② 次のプログラムで出力される 3つの値は、それぞれいくつか答えてください。

#include <stdio.h>

int main(void)
{
    short snum = 1000;
    short num1 = snum + snum;
    short num2 = (int)snum + (int)snum;
    short num3 = (int)(snum + snum);

    printf("%hd\n", num1);
    printf("%hd\n", num2);
    printf("%hd\n", num3);
}


いずれも 2000 が出力されます。

実行結果:

2000
2000
2000

いずれにせよ、short型の値は整数拡張によって int型に変換されます。num1 では、int型の 1000 + 1000 の結果である 2000 を、short型の変数に入れるため、short型に再変換されますが、2000 は short型でも表現できるので問題ありません。

num2 のところは、整数拡張をキャストで明示的にしているだけです。num1 の場合と同じで、2000 は short型でも表現できるので、問題なく 2000 になります。

num3 の場合、まず snum が整数拡張で int型に変換されます。その計算結果もまた int型ですから、int型へのキャストには特に意味がありません。これも最終的に short型に変換されますが、やはり問題なく 2000 になります。

問題③

問題③ 次のプログラムを、出力される値が 0.47 になるように修正してください。 何通りの修正方法が考えられますか?

#include <stdio.h>

int main(void)
{
    int num = 47;

    printf("%f\n", num / 100);
}


まず、このままでは正しく 0.47 が出力されないのは、int型で計算しているからです。 int型の変数num を int型の 100 で割っていますから、その結果は 0 になってしまいます。

次のようにキャストを使う方法が考えられます。

#include <stdio.h>

int main(void)
{
    int num = 47;

    printf("%lf\n", (double)num / 100);
}

実行結果:

0.470000

あるいは、次のようにします。

#include <stdio.h>

int main(void)
{
    int num = 47;

    printf("%lf\n", num / (double)100);
}

実行結果:

0.470000

いずれも、キャストによって double型に変換しています。計算の際、一方が double型であれば、他方も double型に拡張され、結果も double型になります。

またはキャストを使わず、100100.0 に変えれば double型になりますから、これでも構いません。

#include <stdio.h>

int main(void)
{
    int num = 47;

    printf("%lf\n", num / 100.0);
}

実行結果:

0.470000

変数num の方を、最初から double型にしておくことも考えられます。

#include <stdio.h>

int main(void)
{
    double num = 47.0;

    printf("%lf\n", num / 100);
}

ここまでに挙げたどの方法も、別段、どれが優れているということはありません。また、組み合わせても構いません。いろいろとやり方があるということが理解できれば良いでしょう。


参考リンク


更新履歴

’2018/6/4 第30章から練習問題⑩を移動してきて、練習問題④とした。

’2018/2/23 全面的に文章を見直し、修正を行った。

’2018/1/28 「浮動小数」という表記を、「浮動小数点数」に修正。

’2013/12/2 printf関数に %lf を指定していた箇所を %f に修正。

’2009/7/10 新規作成。



第21章のメインページへ

C言語編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る