トラック5・📦変数・型・演算子

型変換——暗黙と明示

読む目安 約12分・ゴール:暗黙の型変換が起きる方向を知り、キャストで意図を明示できる

アプリでこのトピックを学ぶ(無料・登録不要)

このトピックの要点

Cは型の違う値どうしの計算を、黙って調整して実行します。便利ですが、黙っているぶん事故にも気づきにくい。自動で起きる変換と、自分で指示する変換を分けて押さえます。

暗黙の型変換——自動で起きる

#include <stdio.h>

int main(void) {
    int    n = 3;
    double d = 1.5;
    double kekka = n + d;   // n が 3.0 に変換されてから足される

    printf("%.1f\n", kekka);
    return 0;
}

出力は 4.5。intとdoubleを混ぜると、情報が失われない方向(int → double)へ揃えてから計算されます。これが暗黙の型変換です。char と int を混ぜたときも同じで、char が int に格上げされます。

逆向きは削られる

#include <stdio.h>

int main(void) {
    double nedan = 199.9;
    int    seisuu = nedan;    // 小数点以下が消える
    char   chiisai = 300;     // char に収まらない

    printf("%d\n", seisuu);
    printf("%d\n", chiisai);
    return 0;
}

seisuu は 199 です。四捨五入ではなく切り捨て。chiisai は 300 にはならず、44 のような別の値になります(1バイトに300は入らないため)。どちらもエラーにはならず、警告が出る程度で通ってしまいます。

明示の型変換(キャスト)——自分で指示する

#include <stdio.h>

int main(void) {
    int tokuten = 173;
    int ninzuu = 4;

    printf("%.2f\n", (double)tokuten / ninzuu);
    printf("%d\n", (int)(3.7 + 0.5));
    return 0;
}

(型名)値 と書くのがキャストです。1つ目は 43.25——(double) を片方に付けるだけで、計算全体が小数の世界に移ります。2つ目は 4。+0.5 してから (int) で切り捨てることで、正の数の四捨五入になります(定番の書き方です)。

罠・注意

キャストは「変換の命令」であって「安全宣言」ではない。 (char)300 と書けば警告は消えますが、値は壊れたままです。警告を消すためだけのキャストは、バグを隠す行為になります。

割り算のキャストは「割る前」に。 (double)(a / b) では手遅れ。(double)a / b と書きます。

double → int は常に切り捨て。 -2.7 は -2 です(0の方向へ)。

大きい型へは安全、小さい型へは危険。 int → double は安全、double → int や long long → int は情報が消えます。

ビット「自動で合わせてくれる」は、裏を返すと「勝手に決められる」。型を混ぜるときだけは、どっちに揃うか意識してみて。

まとめ

型が混ざると、情報が失われない方向(int → double)へ自動で揃えられます。逆向きの代入では切り捨てや情報落ちが黙って起きます。意図があるときは (double) のようにキャストで明示し、割り算では必ず「割る前に」変換します。

アプリでこのトピックを学ぶ(無料・登録不要)

確認問題

確認問題 1

次のコードを実行したとき、b の値はどれですか。

int a = 5;
double b = a / 2 + 0.5;
  1. 3.0
  2. 2.5
  3. 2.0
  4. 3.5
答えを見る

正解:B(2.5)

a / 2 は int どうしなので 2(2.5 の切り捨て)。そこに 0.5 を足す段階で初めて double へそろえられ、2 + 0.5 = 2.5 になります。3.0 になると考えた人は、a / 2 が 2.5 のまま計算されると思っていたはずです。混ざるのは足し算の時点で、割り算はもう終わっているのがポイントです。

確認問題 2

平均が 43.25 になるはずなのに 平均 43.00 と表示されます。バグのある行はどれですか。

1#include <stdio.h>
2
3int main(void) {
4    int goukei = 173;
5    int ninzuu = 4;
6    double heikin = goukei / ninzuu;
7    printf("平均 %.2f\n", heikin);
8    return 0;
9}
答えを見る

バグのある行:6行目

6行目の右辺 goukei / ninzuu は int どうしの割り算なので、43 に切り捨てられてから double に入っています。double heikin = (double)goukei / ninzuu; と、割る前にキャストします。(double)(goukei / ninzuu) では壊れた後で変換するだけなので直りません。

変数の型(double)ではなく、式が計算される時点の型が結果を決めます。int と double が混ざれば double にそろいますが、int どうしだけの式は最後まで int の世界で計算されます。平均・割合・単価の計算では、まずここを疑います。

「変数・型・演算子」の目次

  1. 変数とは名前付きの箱
  2. int型と整数の世界
  3. 浮動小数点数 float / double
  4. char型と文字コード
  5. bool型と真偽——C23標準の書き方
  6. 定数——const と constexpr
  7. 算術演算子と優先順位
  8. 整数の割り算と剰余の罠
  9. 型変換——暗黙と明示
  10. 2進数・16進数リテラル(0b / 0x / 桁区切り')
  11. sizeofとメモリ上のサイズ
  12. オーバーフローという事件

もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。

完全版の販売ページは準備中です。

ほかのトラック

📚 姉妹教材:手を動かして覚える Linux 教材 — Linuxとインフラの仕組みを地図で学ぶ

Web版