これが私がやりたいことです:
const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);
RandomUintNumberのタイプはuint64_t
。
エラーは(MSVC 2010)です:
エラーC2440: 'reinterpret_cast': 'constuint64_t'から 'int64_t'に変換できません1>変換は有効な標準変換であり、暗黙的に、またはstatic_cast、Cスタイルのキャスト、または関数スタイルのキャストを使用して実行できます。
なぜコンパイルされないのですか?どちらのタイプも同じビット長ですが、reinterpret_castの目的ではありませんか?
それはreinterpret_cast
の目的ではないからです。 reinterpret_cast
で許可されているすべての変換には、整数型または列挙型がそれ自体に対してreinterpret_cast
である可能性があることを除いて、ポインターまたは参照が含まれます。これはすべて、標準[expr.reinterpret.cast]
で定義されています。
ここで何を達成しようとしているのかはわかりませんが、randomIntNumber
にrandomUintNumber
と同じ値を設定したい場合は、
const int64_t randomIntNumber = randomUintNumber;
その結果、コンパイラの警告が発生する場合、またはより明確にしたい場合は、次のようにします。
const int64_t randomIntNumber = static_cast<int64_t>(randomUintNumber);
randomUintNumber
が2未満の場合、キャストの結果は入力と同じ値になります63。それ以外の場合、結果は実装定義ですが、int64_t
を持つすべての既知の実装は、明らかなことを行うように定義することを期待しています。結果は、2を法とする入力と同等です。64。
randomIntNumber
にrandomUintNumber
と同じビットパターンを持たせたい場合は、次のようにすることができます。
int64_t tmp;
std::memcpy(&tmp, &randomUintNumber, sizeof(tmp));
const int64_t randomIntNumber = tmp;
int64_t
は2の補数表現を使用することが保証されているため、実装がstatic_cast
の範囲外の値に対して、これと同じ結果になるようにuint64_t
を定義することをhopeします。ただし、標準のAFAIKでは実際には保証されていません。
randomUintNumber
がコンパイル時定数であっても、残念ながらここではrandomIntNumber
はnotコンパイル時定数です。しかし、それでは、コンパイル時定数はどの程度「ランダム」なのでしょうか。 ;-)
それを回避する必要があり、範囲外の符号なし値を符号付き型に変換することについて実装が賢明であると信頼できない場合は、次のようになります。
const int64_t randomIntNumber =
randomUintNumber <= INT64_MAX ?
(int64_t) randomUintNumber :
(int64_t) (randomUintNumber - INT64_MAX - 1) + INT64_MIN;
今、私は可能な限り真にポータブルなコードを書くことに賛成ですが、それでもこれはパラノイアの危機に瀕していると思います。
ところで、あなたはこれを書きたくなるかもしれません:
const int64_t randomIntNumber = reinterpret_cast<int64_t&>(randomUintNumber);
または同等に:
const int64_t randomIntNumber = *reinterpret_cast<int64_t*>(&randomUintNumber);
int64_t
とuint64_t
が存在する場合、同じサイズの符号付き型と符号なし型であることが保証されていますが、実際には標準整数の符号付きバージョンと符号なしバージョンであることが保証されていないため、これが機能することは完全には保証されません。タイプ。したがって、このコードが厳密なエイリアシングに違反しているかどうかは、実装固有です。厳密なエイリアシングに違反するコードの動作は未定義です。以下はnot厳密なエイリアシングに違反しており、randomUintNumber
のビットパターンがlong long
の値の有効な表現である場合は問題ありません。
unsigned long long x = 0;
const long long y = reinterpret_cast<long long &>(x);
したがって、int64_t
とuint64_t
がlong long
とunsigned long long
のtypedefである実装では、私のreinterpret_cast
は問題ありません。そして、範囲外の値の符号付き型への実装定義の変換と同様に、実装が行うのが賢明なことは、それらを対応する符号付き/符号なし型にすることであるとexpectします。したがって、static_cast
や暗黙の変換と同様に、適切な実装で機能することを期待しますが、実際には保証されていません。
このような場合はstatic_cast
を使用してください。言語設計者は、すべての知恵で、reinterpret_cast
を正当化するのに「十分に安全ではない」とは見なされないと判断したと思います。
いいえそうではありません。 reinterpret_cast
は主に、既存のストレージビットを実際とは異なるタイプとして再解釈することを目的としています。これらの解釈の多くは実装に依存しており、標準ではreinterpret_cast
(主に異なるポインター/参照型間でキャスト)で実行できる特定の(ここで引用するのはかなり長い)リストがリストされていますが、次のように述べています。
Reinterpret_castを使用して他の変換を明示的に実行することはできません。
あなたの場合、既存のストレージの再解釈ではなく、タイプの変換が必要になる可能性があります。この目的にはstatic_cast
を使用します。
reinterpret_cast
は、オブジェクトのストレージを別のオブジェクトとして再解釈するために使用されます。標準的な表現を使用したくない場合は、reinterpret_cast
で実行できるすべてのことを見つけることができます ここ 。一般に、ポインタ型を操作する必要があることを覚えておいてください。
したがって、uint64_t
に使用されているビットをint64_t
として本当に再解釈したい場合は、次のようにします。
int64_t randomIntNumber = reinterpret_cast<int64_t&> (randomUintNumber);
ただし、オブジェクトを変換するだけの場合は、可能であればその値を保持します...コンパイラが提案することを実行し、代わりにstatic_cast
を使用します。
C++ 11標準(N3376)5.2.10.1から:
Reinterpret_castを使用して明示的に実行できる変換を以下に示します。 reinterpret_castを使用して他の変換を明示的に実行することはできません。
許可される整数型から整数型への唯一の変換は、型が同一である場合に事実です。
その他にはポインタが含まれます。
なぜコンパイルされないのですか?
どちらの型もポインタではないからです。
両方のタイプのビット長は同じですが、
なぜそれが重要なのでしょうか?それらがポインタである場合、同じサイズのものを指していることが重要かもしれませんが、それらはポインタではありません。
reinterpret_castの目的ではありませんか?
いいえ、reinterpret_cast
はポインタキャスト用です。キャストの内側に&
を置き、キャストの外側に*
を置くことで、やりたいことができます。それがキャストの再解釈の目的です。