C言語 明示的キャストと暗黙のキャストの違い【使う時の注意点】

C言語
この記事は約7分で読めます。

こんにちは、ナナです。

「キャスト」とはデータ型を合わせこむ機能であり、演算や代入といったシーンにおいて必要な時があります。

キャストは「正しく使うこと」が必要であり、意味を分かった上で利用することが求められます。

本記事では次の疑問点を解消する内容となっています。

本記事で学習できること
  • キャストの役割と種類とは?
  • 暗黙のキャストの使われ方とは?
  • 明示的なキャストの使い方とは?
  • 明示的なキャストを使う時の注意点とは?

では、キャストの使い方を学んでいきましょう。

スポンサー

キャストの役割と種類

「キャスト」は正しく使うことが必要なんですね。では、キャストについての正しい知識を知りたいです。

プロテインも正しい飲み方をすることで、この筋肉が増強されるんですよ!

ナナ
ナナ

それじゃあ、「キャスト」っていうものがどんなものかを、まずは学んでいこうね。

「キャスト」はプログラムを利用していると、皆さんの知らないところで活躍していたりします。

#include <stdio.h>

int main(void)
{
	long price = 10000;

	printf("%lf", price * 1.08);

	return 0;
}

ひとつの例ですが、このような「整数型×浮動小数点型」の演算の場合、「浮動小数点×浮動小数点」として演算が行われます。

このような、データ型を合わせこむ機能を「キャスト」と呼びます。

キャストの種類

キャストの種類には次のものがあります。

キャストの種類
  • 明示的なキャスト
  • 暗黙のキャスト

C言語ではデータ型の異なる変数に対して代入や演算をする時に、データ型を合わせこむ仕組みが働きます。

データ型には優先順位があり、次の順で優先度の高い型へと型変換が行われます。

データ型の優先度
ナナ
ナナ

データサイズや精度において、より大きい方にデータ型は合わせこまれます。

キャストとコンパイラの関係性

「キャスト」というテーマは「コンパイラ」とつながりが深い機能です。

コンパイラには、プログラムの間違いを検知する校正機能と、ソースコードを解釈して機械語にする翻訳機能が備わっています。

コンパイラについて詳しくは『C言語 コンパイラの役割【エラーの取り除き方の鉄則教えます】』を見ておきましょう。

スポンサー

暗黙のキャストの使われ方

キャストには2種類あるんですね。「暗黙のキャスト」って変わった名前ですけど「暗黙のルール」みたいな意味の暗黙ですか?

ナナ
ナナ

そうだね。「暗黙のキャスト」はプログラムとして明確化していなくても、実施されるキャストのことだね。まずはこれを紹介しようね。

暗黙のキャストは、自然な形で行われるタイプの型変換です。

暗黙のキャスト:実例その1

最初の例として紹介したこちらにプログラムは、代表的な「暗黙のキャスト」が作用しているケースです。

#include <stdio.h>

int main(void)
{
	long price = 10000;

	// 整数型 x 浮動小数点型 
	//   ==> 浮動小数点型 x 浮動小数点型
	printf("%lf", price * 1.08);

	return 0;
}

このように異なるデータ型が混在する演算は、暗黙のキャストにより自動的に優先順位の高いデータ型に合わせて演算が行われます。

暗黙のキャスト:実例その2

暗黙のキャストが作用するその他のケースは、小さなデータ型から大きなデータ型への代入処理です。

#include <stdio.h>

int main(void)
{
    short   num1 = 1000;
    long    num2;

    // short ==> long
    num2 = num1;

    return 0;
}

このプログラムは、ビルドをしてもエラーや警告は出力されません。

short型とlong型は共に整数を管理するデータ型であり、「long型」は「short型」よりもサイズが大きいですね。

そのため、「short型変数」の中身を「long型変数」は、そのまま受け入れることができます。

暗黙のキャストのイメージ

これは「小さいバケツの水を、大きなバケツに移し替えても溢れることがない」ということであり、コンパイラは安全であると判断しているからです。

ナナ
ナナ

「暗黙のキャスト」はコンパイラが安全だと判断し、自動的にデータ型を拡張してくれる機能です。

スポンサー

明示的なキャストの使い方

「暗黙のキャスト」は特に何もしなくても勝手に行ってくれるんですね。じゃあ、「明示的キャスト」って自分で「明示」するってことなんですか?

私は筋肉の大きさを、この肉体を持って明示しているんですよっ!

ナナ
ナナ

その通り、なかなかの考察力だね。「明示的キャスト」はみんなの明確な意思で行うキャストなんだよ。

明示的なキャストは、プログラマーが「キャストします」と明記することで実施されます。

暗黙のキャストで対処できない場合の問題

まず、暗黙のキャストで対処しきれない問題のケースを示します。

データ型の優先順位に従わない代入は、次のようにエラーや警告が出力されます。

#include <stdio.h>

int main(void)
{
	long  num1 = 100000;
	short num2;

	// long ==> short
	num2 = num1;

	return 0;
}

ビルドを行うと、コンパイラによって次の警告が検知されます。

main.c(9): warning C4244: '=': 'long' から 'short' への変換です。データが失われる可能性があります。

long型の格納範囲は非常に広く、short型は3万程度の数値までしか格納できません。

そのため、代入した際に「数が溢れる可能性があるけど大丈夫?」と、コンパイラが警告しているわけです。

型あふれ

このプログラムは「num1変数」の値が100であっても出力されます。つまり、コンパイラは情報が溢れる可能性に対して警告を行っているということです。

明示的キャストを使った型の強制変換

では、明示的なキャストを使ったケースを示しましょう。

#include <stdio.h>

int main(void)
{
	long	num1 = 100;
	short	num2;

	// キャストを使って明示的に型の強制変換
	num2 = (short)num1;

	return 0;
}

このように変数や数値の前に(データ型名)を明記することで、明示的キャストによる型の強制変換ができます。

ただし、このキャストは警告の指摘が消えたということだけであり、データが溢れないことを検証したうえでキャストすべきかを決定する必要があります。

ナナ
ナナ

「明示的キャスト」は皆さん自身が行う必要があるため、使う時には注意が必要です。間違えて使うと危険なんですよ。

スポンサー

明示的なキャストを使う上での注意点

警告が出ても「明示的キャスト」を使いまくれば、コンパイラの警告を消せるんですね。たくさん出てきて困ってたんですよ、フフフ。

ナナ
ナナ

その考え方はすごく危険だね。

「明示的キャスト」は、警告を消すのが目的で使う機能じゃないんだよ。本来あるべきデータ型で、処理を行わせるための機能なんだよ。

コンパイラは校正機能によって、データ型の正当性に対して厳しくチェックを行います。

型の違いとは問題を起こしやすく、コンパイラは怪しい処理を見つけては警告やエラーを通知します。

「明示的なキャスト」というのは、

コンパイラのチェックをすり抜けるための変装

とも言えます。

コンパイラの型チェック

コンパイラはプログラマーのミスを検知しようと善意でチェックしているのに、「明示的キャスト」によりチェックをすり抜けてしまうからです。

「キャスト」は状況によって必要なケースもあるのですが、必要悪であると捉え極力使わなくてよいように設計することが最善手です。

型変換が必要になるということは、型の選択がそもそも間違っている可能性に対して目を向けるのです。

ナナ
ナナ

明示的なキャストをするということは、コンパイラの型チェックを無効化することを意味します。

それはデータ型の変換に対して、皆さん自身が型の問題に対して責任を取るということの表明したということです。