fac*_*818 1 c unsigned unsigned-integer
我不擅长C语言,只是遇到了一个我不明白的问题.代码是:
int main()
{
unsigned int a = 100;
unsigned int b = 200;
float c = 2;
int result_i;
unsigned int result_u;
float result_f;
result_i = (a - b)*2;
result_u = (a - b);
result_f = (a-b)*c;
printf("%d\n", result_i);
printf("%d\n", result_u);
printf("%f\n", result_f);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
-200
-100
8589934592.000000
Program ended with exit code: 0
Run Code Online (Sandbox Code Playgroud)
因为(ab)是负的,而a,b是无符号的int类型,(ab)是微不足道的.乘以浮点类型数c后,结果为8589934592.000000.我有两个问题:
首先,为什么在将int类型数字2相乘并分配给int类型数字后,结果是非平凡的?
第二,为什么result_u是非平凡的,即使(ab)是负数,而result_u是无符号的int类型?
我使用Xcode测试此代码,编译器是默认的APPLE LLVM 6.0.
谢谢!
你的假设a - b是负面的是完全错误的.
由于a和b具有unsigned int这两个变量的类型的所有算术运算都是在unsigned int类型的域中执行的.这同样适用于混合" unsigned intwith int"算法.这些操作实现模运算,模数等于UINT_MAX + 1.
这意味着表达式a - b产生类型的结果unsigned int.它是一个大的正值等于UINT_MAX + 1 - 100.在具有32位的典型平台上,int它是4294967296 - 100 = 4294967196.
表达式(a - b) * 2也会产生类型的结果unsigned int.它也是一个很大的正值(UINT_MAX + 1 - 100乘以2并取模UINT_MAX + 1).在一个典型的平台上4294967096.
后一个值对于类型来说太大了int.这意味着当您将其强制转换为变量时result_i,会发生有符号整数溢出.赋值时有符号整数溢出的结果是实现定义的.在你的情况下result_i最终成为-200.它看起来"正确",但语言无法保证这一点.(尽管可能会通过您的实施来保证.)
变量result_u接收正确的无符号结果 - 正值UINT_MAX + 1 - 100.但是您使用%d格式说明符打印该结果printf,而不是正确的%u.打印unsigned int不符合int使用%d说明符范围的值是非法的.出于这个原因,代码的行为是未定义的.-100您在输出中看到的值只是该未定义行为的一种表现形式.这种输出正式毫无意义,即使它在第一眼看上去是"正确的".
最后,变量result_f接收(a-b)*c表达式的"正确"结果,计算时没有溢出,因为乘法是在float域中执行的.你看到的是我上面提到的大的正值,乘以2.它可能会舍入到float类型的精度,这是实现定义的.确切的价值是4294967196 * 2 = 8589934392.
人们可以争辩说,你打印的最后一个值是唯一一个正确反映无符号算术属性的值,即它是"自然地"从实际结果中得出的a - b.