コンピュータサイエンスでは、型変換[ 1 ] [ 2 ] 、 型キャスト[ 1 ] [ 3 ] 、型強制[ 3 ]、および型ジャグリング[ 4 ] [ 5 ]は、式をあるデータ型から別のデータ型に変換するさまざまな方法です。例としては、整数値を浮動小数点値または文字列としてのテキスト表現に変換すること、およびその逆が挙げられます。型変換は、型階層またはデータ表現の特定の機能を利用できます。型変換の 2 つの重要な側面は、それが暗黙的に(自動的に) 行われるか明示的に行われるか[ 1 ] [ 6 ]、および基となるデータ表現が、ある表現から別の表現に変換されるか、または特定の表現が単に別のデータ型の表現として再解釈されるかです。 [ 6 ] [ 7 ]一般に、プリミティブデータ型と複合データ型の両方を変換できます。
各プログラミング言語には、型の変換方法に関する独自のルールがあります。厳密な型付けを持つ言語は、通常、暗黙的な型変換をほとんど行わず、表現の再解釈を推奨しません。一方、弱い型付けを持つ言語は、データ型間で多くの暗黙的な型変換を行います。弱い型付けを持つ言語では、コンパイラにデータ項目を異なる表現として任意に解釈させることが可能です。これは、一見分かりにくいプログラミングエラーである場合もあれば、基盤となるハードウェアを直接扱うための技術的な手法である場合もあります。
ほとんどのプログラミング言語では、「型強制」という言葉は、コンパイル時または実行時に行われる暗黙的な型変換を表すために使用されます。たとえば、整数と浮動小数点数が混在する式(5 + 0.1 など)では、コンパイラは整数表現を自動的に浮動小数点表現に変換し、小数点以下の桁が失われないようにします。明示的な型変換は、追加のコード(型識別子の追加や組み込みルーチンの呼び出しなど)を記述するか、コンパイラが型不一致で停止する場合に使用する変換ルーチンを記述することによって示されます。
Pascal、Modula-2、Ada、DelphiなどのALGOLライクな言語のほとんどでは、変換とキャストは明確に異なる概念です。これらの言語では、変換とは、暗黙的または明示的に値をあるデータ型の格納形式から別のデータ型の格納形式に変更することを指します。たとえば、16ビット整数を32ビット整数に変更する場合などです。変換の結果、精度の低下や切り捨てなど、格納要件が変わる可能性があります。一方、キャストとは、ある型の値を表すビットパターンの解釈を明示的に別の型に変更することを指します。たとえば、32個の連続したビットは、32個のブール値の配列、4バイトの文字列、符号なし32ビット整数、またはIEEE単精度浮動小数点値として扱われます。格納されているビットは変更されないため、プログラマは、意味のあるキャストを行うために、表現形式、バイト順序、アライメント要件などの低レベルの詳細を知っておく必要があります。
C言語ファミリーやALGOL 68では、通常「キャスト」という言葉は明示的な型変換(暗黙的な型変換とは対照的に)を指すため、これがビットパターンの再解釈なのか、実際のデータ表現の変換なのかについて曖昧さが生じる。より重要なのは、ポインタがどのデータ型(またはクラス)を指すか、そしてオブジェクト(クラス)の継承などの場合にコンパイラがポインタをどのように調整するかについて適用される方法や規則が多数存在することである。
暗黙的な型変換(強制変換または型ジャグリングとも呼ばれる)は、コンパイラによる自動的な型変換です。プログラミング言語によっては、コンパイラが強制変換を行うことを許可しているものもあれば、必須としているものもあります。
混合型式では、プログラムが正しく動作するように、実行時に必要に応じて1つ以上のサブタイプのデータをスーパータイプに変換できます。たとえば、次のコードは有効なC言語コードです。
double d ; long l ; int i ;if ( d > i ) { d = i ; }if ( i > l ) { l = i ; }if ( d == l ) { d *= 2 ; }d、l、i は異なるデータ型に属していますが、比較または代入が実行されるたびに自動的に同じデータ型に変換されます。この動作は、意図しない結果が生じる可能性があるため、注意して使用する必要があります。浮動小数点から整数への表現の変換では、浮動小数点値の小数部分が切り捨てられる(ゼロに丸められる)ため、データが失われる可能性があります。逆に、整数から浮動小数点への表現の変換では、浮動小数点型が一部の整数型の可能なすべての値を正確に表現できない場合があるため、精度が失われる可能性があります。たとえば、はIEEE 754単精度型である可能性があり、整数 16777217 を正確に表現することはできませんが、32 ビット整数型は表現できます。これは、次のコードで示されているように、直感に反する動作につながる可能性があります。float
#include <stdio.h>int main ( void ) { int my_int = 16777217 ; float my_float = 16777216.0 ; printf ( "整数は: %d \n " , my_int ); printf ( "浮動小数点数は: %f \n " , my_float ); printf ( "両者の等価性: %d \n " , my_int == my_float ); }float型をIEEE単精度、int型を少なくとも32ビットとして実装するコンパイラでは、このコードを実行すると次のような奇妙な出力が得られます。
整数は16777217です。 浮動小数点数は 16777216.000000 です。 彼らの平等:1
上記の最後の行では、1 は等価性を表しています。この奇妙な動作は、i_valueと を比較する際に、 が float 型に暗黙的に変換されることが原因ですf_value。この変換によって精度が失われ、比較前に値が等しくなってしまいます。
重要なポイント:
float切り捨て、つまり小数部分の削除をint引き起こします。doublefloat数字の丸め処理を引き起こします。longint余分な上位ビットが失われる原因となる。暗黙的な型変換の特殊なケースとして、型昇格があります。これは、オブジェクトが元の型のスーパーセットを表す別のデータ型に自動的に変換されるものです。昇格は、算術演算や論理演算を行う前に、対象プラットフォームの算術論理演算ユニット(ALU)のネイティブ型よりも小さい型に対してよく用いられます。これは、演算を可能にするため、あるいはALUが複数の型を扱える場合に効率を高めるためです。C言語とC++言語では、ブール型、文字型、ワイド文字型、列挙型、および短整数型のオブジェクトはint型に、float型のオブジェクトはdouble型に昇格されます。他の型変換とは異なり、昇格によって精度が失われたり、オブジェクトに格納されている値が変更されたりすることはありません。
Javaでは:
int x = 3 ; double y = 3.5 ; System.out.println ( x + y ) ; //出力は6.5になります明示的な型変換(型キャストとも呼ばれる)とは、プログラム内で明示的に定義される型変換のことです(暗黙的な型変換に関する言語の規則に従って自動的に行われるのではなく)。これは、プログラム内でユーザーによって要求されます。
double a = 3.3 ; double b = 3.3 ; double c = 3.4 ;int result = static_cast < int > ( a ) + static_cast < int > ( b ) + static_cast < int > ( c ); // result == 9 // 暗黙的な型変換が使用される場合 (「result = a + b + c」のように)、result は 10 になります明示的な型変換にはいくつかの種類がある。
オブジェクト指向プログラミング言語では、オブジェクトをダウンキャストする こともできます。つまり、基底クラスへの参照を、その派生クラスのいずれかにキャストするのです。
C#では、型変換は安全な方法または安全でない方法 (つまり、C ライクな方法) で行うことができ、前者はチェック型キャストと呼ばれます。[ 9 ]
Animal animal = new Cat ();// if (animal is Bulldog) is Bulldog, else an exception Bulldog b = ( Bulldog ) animal ;// if (animal is Bulldog), b = (Bulldog)animal, else b = null b = animal as Bulldog ;// Cat() への参照を削除し、ガベージコレクションの対象としてマークするanimal = null ;// b == null b = animal as Bulldog ;C++では、C++スタイルのキャスト構文を使用することで同様の効果が得られます。
Animal * animal = new Cat ();// Animal または Bulldog のいずれかがもう一方 (または同じ) から派生している場合にのみコンパイルされますBulldog * b = static_cast < Bulldog *> ( animal );// if (animal is Bulldog), b = (Bulldog*) animal, else b = nullptr b = dynamic_cast < Bulldog *> ( animal );// 上記と同じだが、nullptr が返された場合は例外がスローされる// これは例外処理が回避されているコードでは見られないBulldog & br = static_cast < Bulldog &> ( * animal );// 使用後に動物を解放するdelete animal ; animal = nullptr ;// b == nullptr b = dynamic_cast < Bulldog *> ( animal );Eiffelでは、型変換の概念は型システムの規則に統合されています。代入規則では、 のような代入は、そのソース式 ( ) の型がターゲットエンティティ ( ) の型と互換性がある場合に限り有効であると規定しています。この規則では、と互換性があるとは、ソース式の型がターゲットの型に準拠するか、またはターゲットの型に変換されることを意味します。型の適合性は、オブジェクト指向プログラミングにおける多態性の規則によって定義されます。たとえば、上記の代入では、 の型は、の基となるクラスがの基となるクラスの子孫である場合に、 の型に準拠します。x := yyxyxyx
Rust は、ほとんどのプリミティブ型間で暗黙的な型変換 (強制) を提供しません。ただし、キーワードを使用して明示的な型変換 (キャスト) を実行できますas。[ 10 ]
let x : i32 = 1000 ; println! ( "1000 を u16 で表すと: {}" , x as u16 );静的型システムにおける関連概念として、型アサーションと呼ばれるものがあります。これは、コンパイラに対し、自身の型推論を無視して、特定の型の式を扱うように指示するものです。型アサーションは、安全な場合(実行時チェックが行われる)と安全でない場合があり、型アサーションは、あるデータ型の値を別のデータ型に変換するものではありません。
TypeScriptでは、型アサーションはasキーワードを使用して行われます。[ 11 ]
const myCanvas : HTMLCanvasElement = document . getElementById ( "main_canvas" ) as HTMLCanvasElement ;上記の例では、document.getElementByIdは を返すように宣言されていますHTMLElementが、実際には常に を返すことがわかっています。この場合HTMLCanvasElement、 は のサブタイプですHTMLElement。そうでない場合、 の動作に依存する後続のコードはHTMLCanvasElement正しく動作しません。TypeScript では、実行時に型アサーションのチェックが行われないためです。
TypeScriptでは、実行時に値が特定の型であるかどうかをチェックする一般的な方法はありません。実行時型サポートがないためです。ただし、ユーザーがコンパイラに値が特定の型であるかどうかを伝えるユーザー定義関数を作成することは可能です。このような関数は型ガードと呼ばれ、戻り値の型として宣言されます。x is Typeここで、xはパラメータまたはでありthis、の代わりにが用いられますboolean。
これにより、安全でない型アサーションをコードベース全体に散在させるのではなく、チェッカー関数内に収めることができる。
Goでは、型アサーションを使用してインターフェース値から具体的な型値にアクセスできます。これは、値が具体的な型でない場合、(戻り値が 1 つの場合)パニックを起こし、(戻り値が 2 つの場合)ゼロ値を返すという安全なアサーションです。[ 12 ]
t := i .( T )この型アサーションは、システムiが の型であることを伝えますT。そうでない場合、システムはパニックを起こします。
多くのプログラミング言語は、複数の型の値を保持できる共用型をサポートしています。タグなし共用型は、 CやPL/Iなどの緩やかな型チェックを行う言語だけでなく、オリジナルのPascalにも存在します。これらを使用すると、ある型のビットパターンを別の型の値として解釈できます。
ハッキングにおいて、型キャストとは、型変換を悪用して、変数のデータ型を元の定義とは異なるものに一時的に変更することです。[ 13 ]これにより、型変換において変数が「型キャスト」されて別のデータ型になった後、コンパイラはそのハッキングされた変数をその特定の操作の新しいデータ型として扱うため、ハッカーに機会が生まれます。[ 14 ]
(typecast_data_type) variable…」