[解決済み] Win32 で unsigned int へのダブルキャストが 2,147,483,648 に切り捨てられる
質問
以下のコードをコンパイルしてください。
double getDouble()
{
double value = 2147483649.0;
return value;
}
int main()
{
printf("INT_MAX: %u\n", INT_MAX);
printf("UINT_MAX: %u\n", UINT_MAX);
printf("Double value: %f\n", getDouble());
printf("Direct cast value: %u\n", (unsigned int) getDouble());
double d = getDouble();
printf("Indirect cast value: %u\n", (unsigned int) d);
return 0;
}
出力(MSVC x86)です。
INT_MAX: 2147483647
UINT_MAX: 4294967295
Double value: 2147483649.000000
Direct cast value: 2147483648
Indirect cast value: 2147483649
出力します(MSVC x64)。
INT_MAX: 2147483647
UINT_MAX: 4294967295
Double value: 2147483649.000000
Direct cast value: 2147483649
Indirect cast value: 2147483649
で
マイクロソフトのドキュメント
からの変換で、符号付き整数の最大値について言及されていません。
double
から
unsigned int
.
上記のすべての値
INT_MAX
に切り詰められます。
2147483648
に切り捨てられます。
を使っています。 ビジュアルスタジオ2019 を使用してプログラムをビルドしています。では発生しません。 gcc .
私は何か間違ったことをしているのでしょうか?を安全に変換する方法はありますか?
double
を
unsigned int
?
どのように解決するのですか?
コンパイラのバグか...
anastaciu氏から提供されたアセンブリから、ダイレクトキャストコードの呼び出しは
__ftol2_sse
を呼び出していますが、これは数値を
符号付き長さ
. ルーチン名は
ftol2_sse
になっていますが、float は x87 浮動小数点レジスタにあります。
; Line 17
call _getDouble
call __ftol2_sse
push eax
push OFFSET ??_C@_0BH@GDLBDFEH@Direct?5cast?5value?3?5?$CFu?6@
call _printf
add esp, 8
一方、間接キャストは
; Line 18
call _getDouble
fstp QWORD PTR _d$[ebp]
; Line 19
movsd xmm0, QWORD PTR _d$[ebp]
call __dtoui3
push eax
push OFFSET ??_C@_0BJ@HCKMOBHF@Indirect?5cast?5value?3?5?$CFu?6@
call _printf
add esp, 8
で、double 値をポップしてローカル変数に格納し、それを SSE レジスタにロードして
__dtoui3
を呼び出す...これは double から unsigned int への変換ルーチンです。
直接キャストの動作はC89に準拠しておらず、またそれ以降の改訂にも準拠していません。 にも適合しません。 C89は明確にそう言っています。
整数型の値が符号なし型に変換されるときに行われる再変換操作は、浮動型の値が符号なし型に変換されるときには行う必要がない。したがって、移植可能な値の範囲は [0, Utype_MAX + 1) となります。 .
私は、この問題はもしかしたら
2005 年からのこの続き
- という変換関数がありました。
__ftol2
という変換関数がありましたが、これはおそらくこのコードで動作したことでしょう。
符号付き数値
-2147483647に変換し、符号なし数値として解釈したときに正しい結果を生成していたでしょう。
残念ながら
__ftol2_sse
の置き換えにはなりません。
__ftol2
というのは、最下位ビットをそのまま受け取るのではなく、範囲外のエラーを知らせるために
LONG_MIN
/
0x80000000
となっており、ここで unsigned long と解釈されるのは期待されたものでは全くありません。の動作は
__ftol2_sse
の動作は
signed long
のように、double 値の変換は >
LONG_MAX
を
signed long
に変更した場合、動作は未定義になります。
関連
-
[解決済み】 unsigned int vs. size_t
-
[解決済み] intをenumにキャストするにはどうすればよいですか?
-
[解決済み] mallocの結果はキャストするのですか?
-
[解決済み] .NETでのdecimal, float, doubleの違い?
-
[解決済み] C#でenumからint値を取得する
-
[解決済み] const int*、const int * const、int const *の違いは何ですか?
-
[解決済み] 通貨を表すのにDoubleやFloatを使ってはいけないのですか?
-
[解決済み] C 言語の配列へのポインタ/ポインタの配列の曖昧さ解消
-
[解決済み] JavaでDoubleをIntegerにキャストする
-
[解決済み] 実装依存の挙動を回避した効率的な符号なし→符号ありキャスト
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
構造体の配列--[エラー] '['トークンの前に一次式があることが予想される
-
Solve Dev-c++ [エラー] 'for' ループの初期宣言は、C99 または C11 モードでのみ許可されます。
-
C/C++の再定義
-
C - 添え字の値が配列でもポインタでもベクトルでもないエラー
-
[解決済み] mallocで文字列を確保する
-
[解決済み] C言語の**はどういう意味ですか?
-
[解決済み] C言語では「?」演算子は何をするのですか?
-
[解決済み] C言語における「static」の意味とは?
-
[解決済み] 配列のすべてのメンバーを同じ値で初期化するには?
-
[解決済み] .aファイル、.soファイルとは何ですか?