どうやらコンパイラはそれらを無関係な型と見なしているため、reinterpret_cast
必須です。なぜこれがルールなのですか?
3 に答える
それらは完全に異なるタイプであり、標準を参照してください。
3.9.1 基本型 [basic.fundamental]
1 文字として宣言されたオブジェクト (char) は、実装の基本文字セットのメンバーを格納するのに十分な大きさでなければなりません。このセットの文字が文字オブジェクトに格納されている場合、その文字オブジェクトの整数値は、その文字の単一文字リテラル形式の値と等しくなります。char オブジェクトが負の値を保持できるかどうかは実装定義です。文字は、署名なしまたは署名付きで明示的に宣言できます
。 プレーン char、signed char、および unsigned char は、3 つの異なる型です。 char、signed char、および unsigned char は、同じ量のストレージを占有し、同じ整列要件 ( basic.types); つまり、それらは同じオブジェクト表現を持っています。文字型の場合、オブジェクト表現のすべてのビットが
値表現に関与します。符号なし文字タイプの場合、値表現の可能なすべてのビット パターンは数値を表します。これらの要件は、他のタイプには当てはまりません。特定の実装では、プレーンな char オブジェクトは、signed char または unsigned char と同じ値を取ることができます。どちらが実装定義です。
これに類似しているため、以下が失敗する理由もあります。
unsigned int* a = new unsigned int(10);
int* b = static_cast<int*>(a); // error different types
a
とb
は完全に異なるタイプです。実際にあなたが疑問に思っているのは、次のことを問題なく実行できるのに、なぜ static_cast がそれほど制限的であるかということです
unsigned int a = new unsigned int(10);
int b = static_cast<int>(a); // OK but may result in loss of precision
また、ターゲットの型が同じビット フィールド幅であり、表現できると推定できないのはなぜですか? スカラー型に対してこれを行うことができますが、ポインターに対しては、ターゲットがソースから派生したものであり、ダウンキャストを実行したい場合を除き、ポインター間のキャストは機能しません。
Bjarne Stroustrop はstatic_cast
、このリンクでなぜ が役立つかを述べています: http://www.stroustrup.com/bs_faq2.html#static-castただし、省略形では、ユーザーが自分の意図が何であるかを明確に述べ、コンパイラーに提供する必要があります。は異なるポインター型間のキャストをサポートしていないため、意図したことが達成できることを確認する機会static_cast
。コンパイラーはこのエラーをキャッチしてユーザーに警告し、ユーザーが本当にこの変換を行いたい場合はreinterpret_cast
、
無関係なポインターを static_cast で変換しようとしています。それは static_cast の目的ではありません。ここで見ることができます: Type Casting。
static_cast を使用すると、数値データ (char から unsigned char への変換など) や関連するクラスへのポインター (何らかの継承によって関連付けられる) を変換できます。これはどちらも当てはまりません。無関係なポインターを別のポインターに変換したいので、reinterpret_cast を使用する必要があります。
基本的に、あなたがやろうとしていることは、コンパイラが char * を void * に変換しようとするのと同じことです。
わかりました、ここで、これを許可することが根本的に間違っている理由について、いくつかの追加の考えを示します。static_cast を使用して、数値型を相互に変換できます。したがって、次のように書くことは完全に合法です。
char x = 5;
unsigned char y = static_cast<unsigned char>(x);
可能なこと:
double d = 1.2;
int i = static_cast<int>(d);
このコードをアセンブラーで見ると、2 番目のキャストが d のビット パターンの単なる再解釈ではなく、変換のためのアセンブラー命令がここに挿入されていることがわかります。
ここで、この動作を配列に拡張すると、ビット パターンを解釈する別の方法で十分な場合に、うまくいく可能性があります。しかし、double の配列を int の配列にキャストする場合はどうでしょうか? ここで、単純にビット パターンの再解釈が必要であることを宣言する必要があります。reinterpret_cast と呼ばれるメカニズムがあるか、追加の作業を行う必要があります。ご覧のとおり、ポインター/配列の static_cast を単純に拡張するだけでは十分ではありません。これは、型の単一の値を static_casting するのと同様に動作する必要があるためです。これには追加のコードが必要になる場合があり、配列に対してこれを行う方法を明確に定義することはできません。あなたの場合 - \0 で停止 - それは慣習だからですか? これは、文字列以外のケース (数値) には十分ではありません。データ型のサイズが変更された場合 (例: int と
必要な動作をすべてのユースケースで適切に定義できるわけではないため、C++ 標準に含まれていません。それ以外の場合は、次のようなことを覚えておく必要があります。「整数型で、幅が同じである限り、この型を他の型にキャストできます。」このようにして、それは完全に明確です-それらは関連するCLASSESであり、ポインターをキャストするか、数値型であり、値をキャストできます。
ポインターであることを除けば、共通点はunsigned char *
ありchar *
ません (EdChum はchar
、signed char
とunsigned char
が 3 つの異なるタイプであるという事実を既に述べています)。Foo *
異なる構造体へのBar *
ポインター型についても同じことが言えます。
static_cast
ソース型のポインターを宛先型のポインターとして使用できることを意味します。これには、サブタイプの関係が必要です。したがって、質問のコンテキストでは使用できません。必要なのは、reinterpret_cast
まさにあなたが望むことを行うものか、C スタイルのキャストのどちらかです。