なぜこのreinterpret_castをコンパイルしないのですか?
-
18-09-2019 - |
質問
私はreinterpret_cast
が危険であることを理解し、私はちょうどそれをテストするためにこれをやっています。私は、次のコードを持っています:
int x = 0;
double y = reinterpret_cast<double>(x);
私はプログラムをコンパイルしようとすると、、それは私に言ってエラーになります。
ダブル」と入力するタイプから無効なキャスト「フロート」
何が起こっているの?私はなぜこの単純なキャストがコンパイルされません、reinterpret_cast
あなたは潜水艦にリンゴを変換するために使用することができ、不正なキャストだと思った?
解決
あなたが本当に価値のx
をキャストしていないキャストによって返された値にYを割り当てることで、あなたはそれを変換しています。つまり、y
はx
、それがフロートを指していることふりを指していません。変換は、型float
の新しい値を作成し、それをx
から値を割り当てます。その中で、C ++でこの変換を行うには、いくつかの方法があります:
int main()
{
int x = 42;
float f = static_cast<float>(x);
float f2 = (float)x;
float f3 = float(x);
float f4 = x;
return 0;
}
最後の(暗黙的な変換)である唯一の実質的な違いは、より高い警告レベルの診断コンパイラを生成します。同じマシンコードのように、多くのケースでは、の実際のと同じこと。
- しかし、彼らはすべての機能に同じことを行います。 あなたが本当にx
がfloatであるふりをしたくない場合は、さて、あなたは本当にこれをすることによって、x
をキャストしたいです。
#include <iostream>
using namespace std;
int main()
{
int x = 42;
float* pf = reinterpret_cast<float*>(&x);
(*pf)++;
cout << *pf;
return 0;
}
あなたは、これがどれほど危険かを見ることができます。実際に、私は私のマシン上でこれを実行し、出力は明らかに42 + 1ではない1
、です。
他のヒント
は、C ++ reinterpret_cast
においてのみ明示的言語仕様に記載されているコンバージョンの特定のセットを実行することができます。要するに、reinterpret_cast
のみへのポインタのポインタの変換基準ツー参照コンバージョン(プラスへのポインタ整数および整数へのポインタ変換)を実行することができます。このキャストの非常に名前で発現意図と一致している:ポインタ/参照の再解釈のために使用されることが意図されている
何をしようとしていることは再解釈ではありません。あなたはint
としてdouble
を再解釈したい場合は、参照型に変換する必要があると思います。
double y = reinterpret_cast<double&>(x);
同等のポインタベースの再解釈は、おそらくより明確であるが
double y = *reinterpret_cast<double*>(&x); // same as above
reinterpret_cast
基準/ポインタ型に変換することができながら、得られた参照/ポインタを介してデータを読み取るための実際の試みが未定義の動作を生成することただし、注、。
そして、どのような場合には、これは、当然のことながら、(大きなint
の場合には、あなたがdouble
によって占有メモリを超えて読まれるので)異なるサイズのdouble
とx
とプラットフォーム上であまり意味がないことができます。
だから、最終的にそれはすべてあなたが達成しようとしていたものに帰着します。メモリの再解釈?上記を参照。変換をint
するために、より意味のあるdouble
のいくつかの種類?もしそうなら、reinterpret_cast
は、ここであなたを助けにはなりません。
reinterpret_castは、一般的なキャストではありません。
:C ++ 03仕様のセクション5.2.10.1によると、reinterpret_castはを使用して明示的に実行することができるの変換は以下のとおりです。他の変換はreinterpret_castはを使用して明示的に実行することはできません。
と積分および浮動小数点型の間の変換を説明列挙されたものがない(または整数型の間にも、これは違法reinterpret_cast<long>(int(3));
である)
int
の表現にごdouble
のビットを変換しようとしている場合は、は、のアドレスのない値をキャストする必要があります。また、サイズが一致することを確認する必要があります:
uint64_t x = 0x4045000000000000;
double y = *reinterpret_cast<double *>(&x);
コンパイラはint
とdouble
が異なるサイズを持つオブジェクト可能性があるので、あなたはナンセンスとして書いたものを拒否します。それは確かに危険ですが、あなたは、このように同じ効果を実現することができます:
int x = 0;
double y = *reinterpret_cast<double*>(&x);
あなたはx
の4つのバイトにアクセスしますy
でメモリの8バイトのデリファレンスあなたがint
を記入する際double
と&x
が、その後切り抜いサイズ(のはy
は4バイトであり、x
が8バイトであるとしましょう)している場合ので、これは潜在的に危険ですそして、の4バイト...メモリで次に来るものは何でも(おそらくy
の開始、またはごみ、または何か他の完全に。)
あなたは、二重に整数を変換したい場合は、static_cast
を使用して、それが変換を行います。
あなたがx
するためにいくつかの便利なポインタ型にキャストbyte*
のビットパターン、(たとえば、sizeof(int) / sizeof(byte)
)とのアクセスをアクセスする場合:
byte* p = reinterpret_cast<byte*>(&x);
for (size_t i = 0; i < sizeof(int); i++) {
// do something with p[i]
}
再解釈キャストを使用すると、別のタイプとして、メモリのブロックを再解釈することができます。これは、ポインタ上で実行する必要があります。のまたは参照の
int x = 1;
float & f = reinterpret_cast<float&>(x);
assert( static_cast<float>(x) != f ); // !!
'他の事は、それが原因の奇妙な値が結果として出てくる、または上記のアサートが失敗しないようにするだけでなく、実際にはかなり危険なキャストであるということですが、種類が異なるサイズのものであり、あなたから再解釈ためならば先 『タイプ「』のソース、再解釈参照/ポインタ上の演算はsizeof(destination)
バイトにアクセスします。
sizeof(destination)>sizeof(source)
場合、それは潜在的に、ソースまたは宛先以外の他の変数を、あなたのアプリケーションを殺すかoverwritting、実際の変数のメモリを超えてステップインします
struct test {
int x;
int y;
};
test t = { 10, 20 };
double & d = reinterpret_cast<double&>( t.x );
d = 1.0/3.0;
assert( t.x != 10 ); // most probably at least.
asswet( t.y != 20 );
reinterpret_cast
は最高のポインタのために使用されています。だから、一つのオブジェクトへのポインタは「潜水艦」に変換することができます。
MSDN のから:
reinterpret_cast演算子をすることができ このようにチャー*として変換に使用されます int型*、またはOne_class *へ 本質的にあるUnrelated_class *、 安全ではない。
reinterpret_castは結果 安全に使用することはできません そのに戻ってキャストされている以外の 元の型。他の用途にはで、あります 最高の、移植性ます。
再解釈のアプローチは、不定の結果との奇妙なパスを私を導きました。最後に、私はそれがはるかに良い。このようにmemcpyをすることが判明!
double source = 0.0;
uint64_t dest;
memcpy(&dest, &source, sizeof(dest));
doubleにint型をキャストすると、キャストを必要としません。コンパイラが暗黙的に割り当てを行います。
はreinterpret_castはint *
にdouble *
を鋳造、例えば、ポインタや参照で使用されます。
それは興味深いです。多分それは倍増するキャストを試みる前に浮かぶようにint型からの暗黙的な変換をやっています。 int型フロートタイプは(もちろん、あなたのシステムに依存する)バイト単位で同じ大きさになる傾向があります。