24

これが私がやりたいことです:

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の目的ではありませんか?

4

7 に答える 7

31

それは目的ではないから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);

が263randomUintNumber未満の場合、キャストの結果は入力と同じ値になります。それ以外の場合、結果は実装定義ですが、それを定義するすべての既知の実装は、明らかなことを実行することを期待しています。結果は、 264を法とする入力と同等です。int64_t


randomIntNumberと同じビットパターンが必要な場合は、次のrandomUintNumberように実行できます。

int64_t tmp;
std::memcpy(&tmp, &randomUintNumber, sizeof(tmp));
const int64_t randomIntNumber = tmp;

2の補数int64_t表現を使用することが保証されているため、範囲外の値に対して実装がこれと同じ結果になるように定義することをお勧めします。ただし、標準のAFAIKでは実際には保証されていません。static_castuint64_t

がコンパイル時定数であってもrandomUintNumber、残念ながらここでrandomIntNumberはコンパイル時定数ではありません。では、コンパイル時定数はどの程度「ランダム」なのでしょうか。;-)

それを回避する必要があり、範囲外の符号なしの値を符号付きの型に変換することについて実装が賢明であると信頼できない場合は、次のようになります。

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、同じサイズの符号付き型と符号なし型であることが保証されている場合でも、実際には標準整数型の符号付きバージョンと符号なしバージョンであることが保証されていないため、これが機能することは完全には保証されません。したがって、このコードが厳密なエイリアシングに違反しているかどうかは、実装固有です。厳密なエイリアシングに違反するコードの動作は未定義です。以下は厳密なエイリアシングに違反しておらrandomUintNumber、のビットパターンが次の値の有効な表現である場合は問題ありませんlong long

unsigned long long x = 0;
const long long y = reinterpret_cast<long long &>(x);

したがって、とがandのtypedefである実装ではint64_tuint64_tmyはOKです。また、範囲外の値から符号付き型への実装定義の変換と同様に、実装で行うのが賢明なことは、それらを対応する符号付き/符号なし型にすることであると予想されます。したがって、および暗黙の変換と同様に、適切な実装で機能することを期待しますが、実際には保証されません。long longunsigned long longreinterpret_caststatic_cast

于 2013-01-31T10:20:29.470 に答える
7

static_castこれらの場合に使用します。言語設計者は、すべての知恵で、それを正当化するのに「十分に安全ではない」とは見なされないと判断したと思いますreinterpret_cast

于 2013-01-31T10:14:56.973 に答える
3

いいえそうではありません。reinterpret_cast主に、既存のストレージを別のタイプとして再解釈することを目的としています。reinterpret_castこれらの解釈の多くは実装に依存しており、標準では(主に異なるポインター/参照型間でキャストする)で実行できることの特定の(ここで引用するのはかなり長い)リストがリストされていますが、次のように述べています。

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

あなたの場合、既存のストレージの再解釈ではなく、タイプの変換が必要になる可能性があります。static_castこの目的で使用します。

于 2013-01-31T10:19:07.093 に答える
2

C ++ 11 Standard(N3376)5.2.10.1からこのドキュメント、101ページ

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

許可される積分型から積分型への唯一の変換は、型が同一である場合に実際に行われます。

その他には、ポインターが含まれます。

于 2013-01-31T10:23:14.307 に答える
1

なぜコンパイルされないのですか?

どちらのタイプもポインタではないからです。

両方のタイプのビット長は同じですが、

なぜそれが重要なのでしょうか?それらがポインターである場合、同じサイズのものを指していることが重要かもしれませんが、それらはポインターではありません。

reinterpret_castの目的ではありませんか?

いいえ、reinterpret_castポインタキャスト用です。&キャストの内側と外側を配置することで、やりたいことができます*。それがキャストの再解釈の目的です。

于 2013-01-31T10:21:32.130 に答える
1

reinterpret_castオブジェクトのストレージを別のオブジェクトとして再解釈するために使用されます。標準的な言い回しを使いたくない場合は、ここでできることをすべて見つけることができreinterpret_castます。一般に、ポインタ型を操作する必要があることを覚えておいてください。

したがって、自分に使用されているビットを本当に再解釈したい場合は、次のuint64_tようint64_tにします。

int64_t randomIntNumber = reinterpret_cast<int64_t&> (randomUintNumber);

ただし、オブジェクトを変換するだけで、可能であればその値を保持したい場合は、コンパイラが提案することを実行して、static_cast代わりに使用してください。

于 2013-01-31T10:25:13.893 に答える
1

ビットパターンをmemcpyで再解釈し、タイプを変換してstatic cast

あなたを使用reinterpret_castすることは違反していstrict aliasingます。未定義の動作になってしまうため、これは悪いことです(新しいコンパイラバージョンでコードが誤動作する可能性があります)。 厳密なエイリアシングルールとは何ですか。は、問題とその解決策を説明するすばらしい記事です(「今、ルールブックへ」という長い部分はスキップしてください;))。コンパイラの最適化はとにかくコピーをスキップすることを推奨memcpyし、主張します。

コード

ここにインタラクティブコード。特定のケースでは、すべてのオプションで同じ結果が得られます。newTypeとで遊ぶと、これは変わりますrandomUintNumber

#include <iostream>
#include <cstring>

int main()
{
    typedef int64_t newType; // try: double, int64_t
    
    uint64_t randomUintNumber = INT64_MAX + 10000; // try: 64000, INT64_MIN, INT64_MAX, UINT64_MAX, INT64_MAX + 10000
    std::cout << "INT64_MIN: " << INT64_MIN << std::endl;
    std::cout << "UINT64_MAX: " << UINT64_MAX << std::endl;
    std::cout << "INT64_MAX: " << INT64_MAX << "\n\n";
    std::cout << "randomUintNumber: " << randomUintNumber << "\n\n";
    
    // const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);
    std::cout << "as \"const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);\" does not work, here are some options ...\n\n";
    
    std::cout << "BAD [undefined behavior!]:" << std::endl;
    const newType a = reinterpret_cast<int64_t&> (randomUintNumber);
    std::cout << "\treinterpret_cast<int64_t&> (randomUintNumber): " << a << std::endl;
    
    const newType b = reinterpret_cast<int64_t&&> (randomUintNumber);
    std::cout << "\treinterpret_cast<int64_t&&> (randomUintNumber): " << b << std::endl;
    
    std::cout << "\nGOOD: " << std::endl;
    const newType c = (int64_t) randomUintNumber;
    std::cout << "\t(int64_t) randomUintNumber [static cast, sometimes reinterprets bit pattern]: " << c << std::endl;
    
    const newType d = static_cast<int64_t>(randomUintNumber);
    std::cout << "\tstatic_cast<int64_t>(randomUintNumber) [the same as before]: " << d << std::endl;
    
    static_assert(sizeof(uint64_t) == sizeof(newType), "should not be taken for granted ...");
    newType eNotConst;
    std::memcpy(&eNotConst, &randomUintNumber, sizeof(uint64_t));
    const newType e = eNotConst;
    std::cout << "\tstd::memcpy(&eNotConst, &randomUintNumber, sizeof(uint64_t)); [definately reinterprets bit pattern]: " << e << std::endl;
    
    
    return 0;
}

出力

INT64_MIN: -9223372036854775808
UINT64_MAX: 18446744073709551615
INT64_MAX: 9223372036854775807

randomUintNumber: 9223372036854785807

as "const int64_t randomIntNumber = reinterpret_cast<int64_t> (randomUintNumber);" does not work, here are some options ...

BAD [undefined behavior!]:
    reinterpret_cast<int64_t&> (randomUintNumber): -9223372036854765809
    reinterpret_cast<int64_t&&> (randomUintNumber): -9223372036854765809

GOOD: 
    (int64_t) randomUintNumber [static cast, sometimes reinterprets bit pattern]: -9223372036854765809
    static_cast<int64_t>(randomUintNumber) [the same as before]: -9223372036854765809
    std::memcpy(&eNotConst, &randomUintNumber, sizeof(uint64_t)); [definately reinterprets bit pattern]: -9223372036854765809
于 2020-08-06T09:47:03.187 に答える