C LANGUAGE TECHNOLOGY

【C言語】キャスト演算子による明示的な型変換【暗黙的な型変換も紹介】

悩んでいる人

C言語のキャスト演算子を教えて!

こういった悩みにお答えします.

本記事の信頼性

  • リアルタイムシステムの研究歴12年.
  • 東大教員の時に,英語でOSの授業.
  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校コンピュータサイエンス学部2021年の世界大学学術ランキングで20位)で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発
  • プログラミング歴15年以上,習得している言語: C/C++Solidity,Java,Python,Ruby,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開

こういった私から学べます.

キャスト演算子【明示的な型変換】

キャスト演算子とは,データ型を別のデータ型に明示的に変換する演算子のことです.

キャスト演算子の書式は,以下のようになります.

例えば,int型からlong型にキャスト演算子で型変換する(キャストする)コードは以下になります.

また,ポインタ型も変換することができます.

int型の変数xのアドレスを指すint型のポインタ変数yを,long型のポインタにキャストして,long型のポインタ変数aに代入するコードは以下になります.

キャスト演算子でオーバーフローの回避

各々のデータ型には扱える値の範囲があり,この範囲を越える値の代入があった場合,データはオーバーフロー(算術オーバーフロー)します.

しかし,C言語では以下のコードのように,オーバーフローしてもエラーメッセージは出力されず,演算は何事もなかったように実行します.

実行結果は以下になります.

GCCでは以下の警告が発生して,オーバーフローを検知できます(2~8行目).

c = -112,data = 0と間違った計算結果になっていますね(10~11行目).

さらに,オーバーフローでは演算の途中でも生じます.

例えば,2147483647+1の計算の答えは2147483648です.

2147483647はint型で,2147483648はlong型で入ります.

※ちなみに2147483647(=2^31-1)はint型の最大値INT_MAXです.

しかし,以下のコードの「a = x + y;」の部分は正常に動作しません.

つまり,「int型 + int型 = long型」とはなりません.

int型 + int型の計算はint型で行われます.

2147483647+1はこの時点でオーバーフローしています.

int型では2147483648という整数は扱えません.

既にオーバーフローした値をlong型変数に代入した結果,間違った値(実行結果は-2147483648と負の値)になります.

演算して式の値を求めることと,代入することはC言語では別の処理になっていることを理解しておかないと,このようなミスをしてしまいます.

この問題はキャスト演算子を利用することで解決できます.

オーバーフローを発生するコードと,キャスト演算子を利用してオーバーフローを回避するコードは以下になります.

実行結果は以下になります.

3行目ではオーバーフローして「2147483647 + 1 = -2147483648」と間違った計算結果になっていますが,4行目ではオーバーフローを回避することで「2147483647 + 1 = 2147483648」と正しい計算結果になっています.

処理系依存の整数と浮動小数点数の最小値と最大値,オーバーフローについて詳しく知りたいあなたはこちらからどうぞ.

【C言語】処理系依存 最小値と最大値
【C言語】処理系依存の整数と浮動小数点数の最小値と最大値の取得

こういった悩みにお答えします. こういった私から学べます. 目次1 処理系依存の整数と浮動小数点数の最小値と最大値の取得2 処理系依存の整数の最小値と最大値の取得3 処理系依存の浮動小数点数の最小値と ...

続きを見る

C言語 算術オーバーフロー
【C言語】算術オーバーフローと回避方法

こういった悩みにお答えします. こういった私から学べます. 目次1 算術オーバーフロー2 整数オーバーフロー3 C言語で符号ありデータ型を使う理由4 符号エラー5 切り捨てエラー6 不完全な範囲チェッ ...

続きを見る

キャスト演算子で汎用ポインタ型(void *)からデータ型ポインタに変換

キャスト演算子で汎用ポインタ型(void *)からデータ型ポインタに変換します.

よくmalloc関数等で動的にメモリ確保する場合,その戻り値の型は汎用ポインタ(void *)なので,データ型ポインタへ明示的にキャストします.

以下に汎用ポインタ型からint型のポインタに変換するコード例を示します.

※「(int *)」と明示的に型変換しなくても動作しますが,以下のようにコードを書くことは定石ですので,覚えておきましょう.

キャスト演算子を利用して動的にメモリ確保する方法を知りたいあなたは,malloc/calloc/realloc/alloca関数と可変長配列で動的にメモリ確保を読みましょう.

C言語 動的メモリ確保
【C言語】malloc/calloc/realloc/alloca関数と可変長配列で動的にメモリ確保

こういった悩みにお答えします. こういった私から学べます. C言語のmalloc/calloc/realloc/alloca関数と可変長配列で動的にメモリ確保する方法を紹介します. 目次1 mallo ...

続きを見る

暗黙的な型変換

暗黙的な型変換は,異なるデータ型同士で演算する際に発生します.

例えば,int型とlong型で演算する時,int型はより大きな型であるlong型に暗黙的な型変換が発生します.

データ型の暗黙的な型変換は以下の関係になります.

signed char<=short int<=int<=long int<=long long int <= float <= double

int型とlong型の演算で暗黙的な型変換

int型とlong型の演算で暗黙的な型変換が発生するコードは以下になります.

このコードは,overflow_cast.cをベースにint型の変数yをlong型に定義を変更したものです.

実行結果は以下になります.

implicit.cの14行目の「a = x + y;」の演算で,xはint型ですがyはlong型なので,暗黙的な型変換でxはlong型に変換されます.

これにより,オーバーフローが発生せずに,x + yの正しい計算結果がaに格納されます.

符号ありのsignedは符号なしのunsignedに暗黙的な型変換

また,符号ありのsignedは符号なしのunsignedに暗黙的な型変換が発生しますので注意して下さい.

以下のコードでよくある間違いを見てましょう.

int型の変数iの値は12行目のfor文でn(値は10)に初期化され,i * n >= 0が成立する場合,for文の中身を実行し,最後にiをデクリメントします.

一見すると,正しく動作するように見えますよね.

それでは,実際に実行してみましょう.

iの値が負になっても実行が終了しません.これはi * nの演算でiは符号ありのint型ですがnは符号なしのint型なので,暗黙的な型変換で符号なしのint型になってしまったからです.

この問題を回避する方法は主に以下の2つです.

  • nを符号ありのint型で定義:9行目を「int n = 10;に変換」
  • キャストで明示的に符号なしのint型に変換:12行目の判定を「(int) (i * n) >= 0」

まとめ

C言語のキャスト演算子による明示的な型変換を紹介しました.

キャスト演算子を利用することで,オーバーフローを回避できることや,汎用ポインタ型(void *)からデータ型ポインタに変換できることがわかりました.

また,キャスト演算子を利用しない暗黙的な型変換も紹介しました.

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

友だち追加

独学が難しいあなたは,C言語を学べるおすすめのオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

-C LANGUAGE, TECHNOLOGY
-, , , , , , , ,