暗黙の型変換

C言語における暗黙の型変換について解説します。

異なる型への代入

C言語では異なる型へ代入を行うと、その型の値に型変換されます。

#include <stdint.h>
#include <stdio.h>

int main(void) {
  int32_t num_i32 = 1000;
  int8_t num_i8 = num_i32;
  
  printf("%d\n", num_i8);
}

出力結果です。

-24

1000のはずが、-24になっていますね。これは、int32_t型からint8_t型へ、暗黙の型変換が行われためです。なぜ「-24」になるのかは、型変換規則を解説するところまで待ってください。

異なる型の関数の引数に渡す

関数の引数に渡すときも、異なる型への代入と同じ暗黙の型変換が行われます。引数の型がint8_tで、呼び出し側で渡している値の型はint32_t型なので、これがint8_t型に変換されます。

#include <stdint.h>
#include <stdio.h>

void print_i8 (int8_t num_i8) {
  printf("%d\n", num_i8);
}

int main(void) {
  int32_t num_i32 = 1000;
  print_i8(num_i32);
}

整数拡張 - int型より小さな値の演算はint型へ変換される

int型より小さな値の演算はint型へ変換されます。これは整数拡張と呼ばれます。これは、整数の四則演算浮動小数点の四則演算を行う場合、単項の「-」を使う場合、比較演算子を使う場合に発生します。

たとえばint8_tの値の演算を行ったとしましょう。int8_tのサイズのまま演算されるのではなく、int型へ型変換され、数値の計算が行われ、再びint8_tに型変換されます。

以下のサンプルでは、型キャストを使って明示的に書いてみました。

#include <stdio.h>
#include <stdint.h>

int main(void) {
  int8_t num1 = 5;
  int8_t num2 = 10;

  /*
    int8_t num3 = num1 + num2;
  */
  // 上記の処理を型キャストを使って明示的に書く
  int8_t num3 = (int8_t)((int)num1 + (int)num2);

  /*
    int8_t num4 = -num3;
  */
  
  // 明示的に書くと上記の処理は以下の記述になる
  int8_t num4 = (int8_t)(-(int)num3);
}

演算において型の順序が小さい方の型は大きい方の型に変換される

整数の四則演算浮動小数点の四則演算を行う場合、単項の「-」を使う場合、比較演算子を使う場合には、型の順序が小さい方の型は大きい方の型に変換されます。

C言語のすべての型順序の規則を覚えておくのは、辛いので、以下の順序だけは、少なくとも覚えておきましょう。

符号あり整数と符号なし整数は、混ぜて使わず、日常的な計算は、符号あり整数と浮動小数点で行っていると想定します。

浮動小数点型と
符号あり整数型の型の順序
(左が大きい)
double, float, int64_t, int32_t, int16_t, int8_t
符号なし整数型の型の順序
(左が大きい)
uint64_t, uint32_t, uint16_t, uint8_t

浮動小数点型は、どの整数型よりも型の順序は大きいです。bit数の大きな整数型は、bit数の小さな整数型よりも大きいです。

以下のサンプルでは、型キャストを使って明示的に書いてみました。int32_t型の値は、型の順序が大きいdouble型に変換されます。

#include <stdio.h>
#include <stdint.h>

int main(void) {
  int32_t num1 = 5;
  double num2 = 10.5;

  /*
    double num3 = num1 + num2;
  */
  // 上記の処理を型キャストを使って明示的に書く
  double num3 = (double)num1 + num2;
  
  printf("%f", num3);
}

関連情報