第4章 型変換

1. 型変換とは

2種類以上の型が混在する式で演算を行う場合、型変換が生じます。型変換の規則を把握していないと、期待通りの結果が得られない場合があります。

型変換には、コンパイラが一定の規則で行う暗黙の型変換と、プログラマがキャスト演算子を用いて行う明示的型変換があります。

2. 暗黙の型変換

コンパイラが自動的に無難な型変換を行うものです。

(1) 代入時の変換

左辺の型と右辺の型が異なっている場合は、左辺の型に変換します。

例えば下の例では、double型変数の x に 浮動小数点数 3.1415 が格納されていても、int型変数 a に代入した時点で小数点以下が切り捨てられて、3 になってしまいます。これは、整数型の int では小数点以下が格納できないために切り捨てられてしまうからです。

double x = 3.1415;
int a = x;    // 小数点以下が切り捨てられて3になる

(2) 式の中で行われる変換

式中で異なる型の定数や変数が現れたときは、精度の高い型に統一します。精度は今まで学習したものでは、下図のように char型 が一番低く、double型が一番高くなります。

char < int < float < double

次の例では、右辺は一番精度の高いdouble型に拡張されて計算されます。その後、そのままdouble型の左辺に代入されています。

int i_dt = 10;
float f_dt = 1.23f;
double d_dt = 3.14;
double d_ans = i_dt * f_dt + d_dt;    // d_ans = 15.44

3. 明示的型変換(キャスト)

強制的に別の型に変換したいときに用います。

次の例では、右辺でint型変数どうしの割り算が行われています。int型は小数点以下を切り捨てますので、右辺の結果は「1」になります。それをdouble型の左辺に代入しますので、左辺は「1.0」になってしまいます。これを回避するには、キャストによって右辺を強制的にdouble型に変換する方法があります。キャストは変換したい型を()で囲み計算式の前に置くことで行えます。この変換は一時的なことで、a と b はあくまでも int型 であることには変わりありません。

#include <stdio.h>

int main(void)
{
    int a = 3;
    int b = 2;
    double result;

    // int型どうしの割り算(小数点以下が切り捨てられる)
    result = a / b;
    printf("キャストなしの結果: result = %f\n", result);  // 結果は 1.000000

    // キャストによって、aをdouble型に変換してから割り算を行う
    result = (double)a / b;
    printf("キャストありの結果: result = %f\n", result);  // 結果は 1.500000

    return 0;
}

【実行結果】
キャストなしの結果: result = 1.000000
キャストありの結果: result = 1.500000

〇 演習問題

問1

次のプログラムを実行すると 変数c に 2.5 が得られると思ったが結果は 2.0 であった。
何が間違いかを指摘し、正しく修正せよ。

#include <stdio.h>
int main( void )
{
    int a = 10, b = 4;
    double c;
    
    c = a / b;
    printf("c = %f\n", c);
    
    return 0;
}

【実行結果例】
c = 2.000000

問2

以下のプログラムの空欄部を埋めて、1個 1234円の品物Aを 12個と、1個 567円の品物Bを8個購入したときの合計金額、および、平均単価をもとめなさい。

#include <stdio.h>

int main(void)
{
    int priceA = 1234;   // 品物Aの単価
    int priceB = 567;    // 品物Bの単価
    int countA, countB;  // 購入個数
    int total;           // 合計金額
    double avg;          // 平均単価

    // 品物A 12個、品物B 8個の場合の合計金額
    countA = 12;
    countB = 8;
    total = ________________________________;

    // 平均単価を求める
    avg = ______________________________;

    printf("合計金額 = %d, 平均単価 = %f\n", total, avg);

    return 0;
}

【実行結果例】
合計金額 = 19344, 平均単価 = 967.200000

解答例

【問1】
ここでの a と b はどちらも int 型であるため、整数どうしの除算が行われます。
整数除算では、小数点以下が切り捨てられるため、10/4 は 2 となり、その結果が double 型の変数 c に代入され、2.0 となってしまいます。

整数除算ではなく、浮動小数点数の除算を行いたい場合は、割り算を行う前に少なくともどちらか一方を double 型にキャストする必要があります。片方の変数をdoubleにキャストすれば暗黙の型変換で「a / b」はdoubleで演算されます。

c = (double)a / b;

こうすることで、a が double 型に変換され、割り算が浮動小数点数として計算され、結果は 2.5 となります。

【問2】
合計金額は、それぞれの単価と購入個数の積の和として求めます。

total = priceA * countA + priceB * countB;

平均単価は合計金額を全購入個数で割って求めます。
ただし、購入個数(countA + countB)は int 型なので、そのまま割ると整数除算になり、小数点以下が切り捨てられます。
そのため、片方または両方のオペランドを double 型にキャストして、正しい浮動小数点の演算結果を得る必要があります。

avg = (double)total / (countA + countB);
// または
avg = total / ((double)(countA + countB));

コメント