C算术转换将无符号与有符号相乘并产生浮点数

Vik*_*dav 3 c

int main()
{
    printf("Hello World\n");
    int x = -10;
    unsigned y = 25;
    float z = x*y;
    printf("x=%d,y=%u,z=%f\n",x,y,z);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我运行上面的代码时,我得到以下输出:

你好世界
x=-10,y=25,z=4294967046.000000

我的问题是:对于第二个 printf,我会期望的z=(float) ( (unsigned)(-10)*25 ) = (float) (4294967286 x 25) = (float) 107374182150,我在这里错过了什么?

pax*_*blo 5

这就是正在发生的事情。根据C11 6.3.1.8 Usual arithmetic conversions(“否则”在这里起作用,因为前面的段落讨论了当任一类型已经是浮点数时会发生什么):

否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则将具有有符号整数类型的操作数转换为具有无符号整数类型的操作数的类型。

这意味着您的有符号值-10变为0xffff'fff6, 或的无符号值4,294,967,286。乘以25给出107,374,182,1500x18'ffff'ff06(这是你想要的结果)。

但是,此时float还没有进行任何计算,乘法是纯整数计算,结果值将是整数。而且,结合您的无符号整数是 32 位长的事实,意味着它被截断为0xffff'ff06, 或4,294,967,046

然后你把放到float.


要解决此问题以匹配您的预期结果,您应该更改他的表达式以强制执行此操作:

float z = 1.0f * (unsigned)x * y;
Run Code Online (Sandbox Code Playgroud)

这将int * unsigned-int计算更改为float * unsigned-int * unsigned-int1。所述unsigned铸造首先确保x将被转换为等效的无符号值,并由乘法1.0f确保乘法是在完成float竞技场避免整数截断。