C++(和 C)中类型转换期间的明显不一致

cap*_*row 3 c++ casting

任何人都可以在这里解释输出吗?我一直试图理解为什么在此代码中对文字进行类型转换的结果与对变量进行类型转换的结果不同。

#include <iostream>
#include <cstdint>

using namespace std;

int main()
{
    double intermediate;
    intermediate = -1.0;
    cout << "intermediate = " << intermediate << endl;
    cout << "uint64_t(intermediate) = " << uint64_t(intermediate) << endl;
    cout << "uint64_t((double)(-1)) = " << uint64_t((double)(-1)) << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我得到的输出是:

intermediate = -1                                                                                                                                   
uint64_t(intermediate) = 18446744073709551615                                                                                                       
uint64_t((double)(-1)) = 0  
Run Code Online (Sandbox Code Playgroud)

dbu*_*ush 5

您正在执行从浮点类型到整数类型的超出范围的转换。

由于 double 值-1.0无法放入 a 中uint64_t,因此这被视为超出范围的转换。这种转换会调用未定义的行为。这意味着,除其他外,两次转换尝试不需要产生相同的结果。

请注意,这与有符号整数到无符号整数的转换不同,后者在所有情况下都有明确定义。

这是由C++17 标准的7.10p1规定的

浮点类型的纯右值可以转换为整数类型的纯右值。转换会截断;也就是说,小数部分被丢弃。如果截断的值无法在目标类型中表示,则行为未定义。

C11 标准的第 6.3.1.4p1 节有类似的语言:

当浮点实型的有限值被转换为除 之外的整数类型时_Bool,小数部分被丢弃(即,该值被截断为零)。如果整数部分的值不能用整数类型表示,则行为未定义。61)

...

61) 当实浮点类型的值转换为无符号类型时,不需要执行整数类型值转换为无符号类型时执行的余数运算。因此,可移植实数浮点值的范围是 (?1,Utype_MAX+1)

要获得一致的结果,您首先需要转换为有符号整数类型,然后转换为无符号类型。

cout << "uint64_t(intermediate) = " << 
        static_cast<uint64_t>(static_cast<int>(intermediate)) << endl;
Run Code Online (Sandbox Code Playgroud)

对于 C:

printf("uint64_t(intermediate) = %llu\n", (uint64_t)(int)intermediate);
Run Code Online (Sandbox Code Playgroud)