先頭へ戻る

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

Programming Place Plus トップページ -- 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型に拡張されます。ここでも特に情報を失うことはないので、-10 のまま比較され、結果は真になります。

3つ目の if文は非常にややこしいです。大抵の環境では偽になるはずですが、真になる可能性もあるかもしれません。

まず、short型の -10 を unsigned short型にキャストしています。この結果、unsigned short型で表現できる最大に近い正の数になってしまうはずです。

比較は、unsigned short型と int型で行おうとしている訳ですが、unsigned short型は変換順位が低いため、整数拡張で変換されます。ここの変換結果が厄介で、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" );
    }

    return 0;
}

実行結果:

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 );

    return 0;
}


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

実行結果:

2000
2000
2000

いずれにせよ、式の中の short型の値は、整数拡張によって、int型に変換されます。 num1 の場合、int型の 2000 を 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 );

    return 0;
}


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

出力したい値は 0.47 という浮動小数点数なので、printf関数の変換指定子は変えられません。従って、printf関数に渡す値の方を、浮動小数点型に仕立てます。

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

#include <stdio.h>

int main(void)
{
    int num = 47;

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

    return 0;
}

実行結果:

0.470000

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

#include <stdio.h>

int main(void)
{
    int num = 47;

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

    return 0;
}

実行結果:

0.470000

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

またはキャストを使わず、定数の 100 を 100.0 と書けば、double型になりますから、これでも構いません。

#include <stdio.h>

int main(void)
{
    int num = 47;

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

    return 0;
}

実行結果:

0.470000

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

#include <stdio.h>

int main(void)
{
    double num = 47.0;

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

    return 0;
}

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

問題④

問題④ 次のプログラム片を見てください。

signed char c1 = 120;
signed char c2 = 60;
signed char c3 = -100;
signed char result = c1 + c2 + c3;

signed char型で表現できる最大値は 127 であり、c1 + c2 の段階で溢れ出してしまうように思えます。実際には、最終的な result の値は、80 となり正しく計算できます。問題が起こらない理由を説明してください。


signed char型同士の計算は、整数拡張の規則によって、int型に拡張されます。従って、120 + 60 + (-100) という計算は int型で行われます。int型の大きさは少なくとも 16ビットはあるので、この程度の大きさの計算では溢れ出しません。

計算結果の 80 は、signed char型の変数result へ代入する際に切り詰められます。しかし、80 であれば signed char型でも表現できるので、ここでも何も問題は起こりません。


参考リンク


------------------------------------------------------------------------

更新履歴

'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 でシェア
Twitter でツイート Twitter をフォロー LINE で送る
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー