1

char* を double に変換し、再び char* に戻そうとしています。次のコードは、作成したアプリケーションが 32 ビットの場合は問題なく動作しますが、64 ビット アプリケーションでは動作しません。この問題は、int から char* に変換しようとすると発生します。たとえば、hello = 0x000000013fcf7888 の場合、変換されるのは 0x000000003fcf7888 で、最後の 32 ビットのみが正しいです。

#include <iostream>
#include <stdlib.h>
#include <tchar.h>
using namespace std;


int _tmain(int argc, _TCHAR* argv[]){

    char* hello = "hello";
    unsigned int hello_to_int = (unsigned int)hello;
    double hello_to_double = (double)hello_to_int;

    cout<<hello<<endl;
    cout<<hello_to_int<<"\n"<<hello_to_double<<endl;

    unsigned int converted_int = (unsigned int)hello_to_double;
    char* converted = reinterpret_cast<char*>(converted_int);

    cout<<converted_int<<"\n"<<converted<<endl;

    getchar();
    return 0;
}
4

6 に答える 6

6

64 ビット Windows では、ポインタは 64 ビットintですが、32 ビットです。これが、キャスト中に上位 32 ビットのデータが失われる理由です。中間結果を保持する代わりにint使用します。long long

char* hello = "hello";
unsigned long long hello_to_int = (unsigned long long)hello;

逆変換についても同様の変更を行います。ただし、double は精度を失うことなく 32 ビット整数の範囲全体を簡単に表すことができますが、64 ビット整数の場合は同じではないため、変換が正しく機能するとは限りません。

また、これはうまくいきません

unsigned int converted_int = (unsigned int)hello_to_double;

その変換では、浮動小数点表現の小数点以下の桁が単純に切り捨てられます。データ型を に変更しても問題は存在しますunsigned long long。あなたはそれをreinterpret_cast<unsigned long long>機能させる必要があります。

それでも、ポインターの値によっては、まだ問題が発生する可能性があります。への変換により、たとえば、double値がシグナル NaNになる可能性があり、その場合、コードが例外をスローする可能性があります。

簡単な答えは、楽しみのためにこれを試していない限り、このような変換を行わないことです。

于 2011-09-26T20:24:32.627 に答える
2

anは 32 ビットであるため、64 ビット Windows ではachar*をキャストできませんが、 aはポインターであるため 64 ビットです。aは常に 64 ビットであるため、 aとの間のキャストを回避できる場合があります。intintchar*doubledoublechar*

于 2011-09-26T20:24:44.987 に答える
1

それがどのシステムでも、どこでも機能するのであれば、幸運なことにすべて自分で進んでください。ポインタを整数に変換することは1つのことです(整数が十分に大きい限り、それを回避できます)が、doubleは浮動小数点数です-何をしているのかは意味がありません。 doubleは、必ずしも任意の乱数を表すことができるとは限りません。ダブルには範囲と精度の制限があり、物事の表現方法にも制限があります。広範囲の値の数値を表すことはできますが、その範囲のすべての数値を表すことはできません。

ダブルには、仮数と指数の2つの要素があることに注意してください。これらを組み合わせることで、非常に大きい数または非常に小さい数を表すことができますが、仮数のビット数は限られています。仮数のビットが不足すると、表現しようとしている数のビットが失われます。

どうやらあなたは特定の状況下でそれをうまくやったようです、しかしあなたはそれが作られていない何かをするようにそれを求めています、そしてそれのためにそれは明らかに不適切です。

ただそれをしないでください-それは機能するはずがありません。

于 2011-09-26T20:33:07.150 に答える
1

任意の整数(具体的にはビットのコレクション)を浮動小数点値にエンコードする際のいくつかの問題:

  1. 64ビット整数から倍精度浮動小数点数への変換は不可逆になる可能性があります。doubleの実際の精度は53ビット2^52であるため、上記の整数(2を追加または追加)は必ずしも正確に表されるとは限りません。
  2. double代わりに(unionまたはを介して)ポインタのビットを再解釈することにしたreinterpret_cast場合でも、有効な二重表現ではないビットのセットとしてポインタをエンコードすると、問題が発生します。値がFPUによって書き戻されないことを保証できない限りdouble、FPUは無効なdoubleを別の無効なdoubleにサイレントに変換できます(NaNを参照)。つまり、同じ値を表すがビットが異なるdouble値です。(浮動小数点形式をビットとして使用することに関連する問題については、これを参照してください。)

32ビットポインタをdoubleにエンコードすることで、53ビットの精度範囲に確実に収まるため、おそらく安全に回避できます。

于 2011-09-26T20:34:03.843 に答える
0

これは予想通りです。

通常、achar*は 32 ビット システムでは 32 ビット、64 ビット システムでは 64 ビットになります。double通常、両方のシステムで 64 ビットです。(これらのサイズは典型的なものであり、Windows ではおそらく正しいものです。この言語では、さらに多くのバリエーションが許可されています。)

ポインターから浮動小数点型への変換は、私の知る限り未定義です。これは、変換の結果が未定義であることを意味するだけではありません。このような変換を実行しようとするプログラムの動作は未定義です。運が良ければ、プログラムがクラッシュするか、コンパイルに失敗します。

ただし、ポインターから整数 (許可されていますが実装定義) に変換し、次に整数から double に変換しています (これは許可されており、意味のある数値に対して意味がありますが、変換されたポインター値は数値的に意味がありません)。 . double の 64 ビットのすべてが数値の大きさを表すために使用されているわけではないため、情報が失われています。通常、指数を表すために 11 程度のビットが使用されます。

あなたがしていることはまったく意味がありません。

正確に何を達成しようとしていますか?それが何であれ、それを行うためのより良い方法は確かにあります。

于 2011-09-26T20:36:21.053 に答える
0

最後の 32 ビットだけが正しいです。

これintは、プラットフォームの が 32 ビット長しかないためです。ポインターを十分なサイズの int に変換できることのみを保証することに注意してreinterpret_castください (あなたのケースではありません)。

于 2011-09-26T20:24:33.843 に答える