74

reinterpret_cast私はそれが危険であることを理解しています、私はそれをテストするためにこれをしているだけです。私は次のコードを持っています:

int x = 0;
double y = reinterpret_cast<double>(x);

プログラムをコンパイルしようとすると、「

タイプ'float'からタイプ'doubleへの無効なキャスト

どうしたの?リンゴを潜水艦に変換するために使用できる不正なキャストだと思いreinterpret_castましたが、なぜこの単純なキャストをコンパイルしないのですか?

4

11 に答える 11

51

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、占有されているメモリを超えて読み取るため)。doubledoublex

つまり、最終的には、達成しようとしていたことになります。記憶の再解釈?上記を参照。変換にとってもっと意味のあるものはありintますか?doubleもしそうなら、reinterpret_castここであなたを助けません。

于 2010-02-05T09:30:04.600 に答える
47

おそらく、より良い考え方は、ポインターを潜水艦へのポインターとしてリンゴにreinterpret_cast「変換」できるルージュ演算子です。

キャストによって返される値にyを割り当てることにより、実際には値をキャストしているのではなくx、変換していることになります。つまり、フロートを指している、または指しているふりをyしないでください。xConversionは、タイプの新しい値を作成し、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さて、もしあなたが本当にそれがフロートであるふりをしたいのなら、あなたは本当にこれをすることxによってキャストしたいのです:

#include <iostream>
using namespace std;

int main()
{
    int x = 42;
    float* pf = reinterpret_cast<float*>(&x);
    (*pf)++;
    cout << *pf;
    return 0;
}

これがどれほど危険かがわかります。実際、これを自分のマシンで実行したときの出力は1、42+1ではないことは明らかです。

于 2010-02-05T06:24:29.080 に答える
12

intのビットをの表現に変換しようとしている場合は、値ではなくアドレスdoubleをキャストする必要があります。また、サイズが一致していることを確認する必要があります。

uint64_t x = 0x4045000000000000;
double y = *reinterpret_cast<double *>(&x);
于 2010-02-05T06:18:22.657 に答える
12

reinterpret_castは一般的なキャストではありません。C ++ 03仕様セクション5.2.10.1によると:

reinterpret_castを使用して明示的に実行できる変換を以下に示します。reinterpret_castを使用して他の変換を明示的に実行することはできません。

そして、整数型と浮動小数点型の間(または整数型の間、これは違法ですが)の変換を説明するものは何もリストされていませんreinterpret_cast<long>(int(3));

于 2010-02-05T06:32:46.180 に答える
6

コンパイラは、サイズの異なるオブジェクトである可能性があるためint、ナンセンスとして記述したものを拒否します。double確かに危険ですが、この方法で同じ効果を得ることができます。

int x = 0;
double y = *reinterpret_cast<double*>(&x);

サイズが異なる場合(たとえば、4バイトで8バイト)、これは潜在的に危険ですx。8バイトのメモリを逆参照して入力すると、4バイトと4バイトにアクセスします...次に来るものは何でもメモリ内(おそらく、の始まり、またはガベージ、または完全に何か他のもの。)yintdouble&xyxy

整数を倍精度整数に変換する場合は、を使用する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]
}
于 2010-02-05T06:24:05.440 に答える
4

再解釈キャストを使用すると、メモリのブロックを別のタイプとして再解釈できます。これは、ポインタまたは参照に対して実行する必要があります。

int x = 1;
float & f = reinterpret_cast<float&>(x);
assert( static_cast<float>(x) != f );   // !!

もう1つは、結果として出てくる奇妙な値や上記のアサーションが失敗しないためだけでなく、型のサイズが異なる場合に「ソース」から「ソース」に再解釈するため、実際には非常に危険なキャストであるということです。 「宛先」タイプ。再解釈された参照/ポインターに対するすべての操作がsizeof(destination)バイトにアクセスします。その場合sizeof(destination)>sizeof(source)、それは実際の変数メモリを超えて、アプリケーションを強制終了したり、ソースまたは宛先以外の他の変数を上書きしたりする可能性があります。

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.
assert( t.y != 20 );
于 2010-02-05T09:11:59.230 に答える
2

再解釈のアプローチは、一貫性のない結果で私を奇妙な道へと導きました。結局、私はこのようなmemcpyの方がはるかに良いと思いました!

double source = 0.0;
uint64_t dest;
memcpy(&dest, &source, sizeof dest);
于 2019-01-25T06:58:28.927 に答える
0

reinterpret_castポインタに最適です。したがって、1つのオブジェクトへのポインタを「潜水艦」に変えることができます。

msdnから:

reinterpret_cast演算子は、char*からint*への変換、またはOne_class*からUnrelated_class*への変換など、本質的に安全ではない変換に使用できます。

reinterpret_castの結果は、元のタイプにキャストバックする以外の目的で安全に使用することはできません。他の用途は、せいぜい、移植性がありません。

于 2010-02-05T06:12:04.973 に答える
0

それは面白い。キャストをdoubleにしようとする前に、intからfloatへの暗黙の変換を行っている可能性があります。int型とfloat型は、バイト単位で同じサイズになる傾向があります(もちろんシステムによって異なります)。

于 2010-02-05T06:19:15.700 に答える
-1

intをdoubleにキャストする場合、キャストは必要ありません。コンパイラーは暗黙的に割り当てを実行します。

reinterpret_castは、ポインタと参照とともに使用されます。たとえば、をにキャストint *double *ます。

于 2010-02-05T06:13:15.367 に答える
-1

ユニオンを使用します。これは、整数型と浮動小数点型の間のメモリマップへのエラーが最も発生しにくい方法です。ポインタを再解釈すると、エイリアシングの警告が発生します。

#include <stdio.h>
#include <stdint.h>

int main(int argc, char *argv[])
{
    union { uint32_t i; float f; } v;  // avoid aliasing rules trouble
    v.i = 42;
    printf("int 42 is float %f\n", v.f);
    v.f = 42.0;
    printf("float 42 is int 0x%08x\n", v.i);
}
于 2020-07-12T14:04:55.340 に答える