我正在阅读关于通常算术转换的C99标准。
如果两个操作数具有相同的类型,则不再进一步转换 需要的。
否则,如果两个操作数都有有符号整数类型或两者都有 无符号整数类型,操作数类型为较小的整数 转换等级转换为具有更大的操作数的类型 秩。
否则,如果具有无符号整数类型的操作数具有等级 那么,大于或等于另一个操作数的类型的等级 带有符号整数类型的操作数转换为 具有无符号整数类型的操作数。
否则,如果带有符号整数类型的操作数的类型可以 表示带有unsigned的操作数类型的所有值 整数类型,然后转换具有无符号整数类型的操作数 到带有符号整数类型的操作数的类型。
否则,两个操作数都将转换为无符号整数类型 对应于带有符号整数类型的操作数的类型。
所以我想说我有以下代码:
#include <stdio.h>
int main()
{
unsigned int a = 10;
signed int b = -5;
printf("%d\n", a + b); /* 5 */
printf("%u\n", a + b); /* 5 */
return 0;
}
我认为粗体段落适用(因为unsigned int
和signed int
具有相同的等级。为什么不将b转换为unsigned
?或者它可能会转换为无符号但是有我不明白的东西?
感谢您的时间: - )
答案 0 :(得分:6)
确实b
已转换为无符号。然而,您观察到的是b
转换为无符号,然后添加到10赋予值5。
在x86 32bit上发生了这种情况
b
,已转为无人签名,变为4294967291
(即2**32 - 5
)2**32
(2**32 - 5 + 10 = 2**32 + 5 = 5
)的环绕,答案 1 :(得分:5)
0x0000000a
加0xfffffffb
将始终为0x00000005
,无论您是处理有符号还是无符号类型。
答案 2 :(得分:3)
从问题中重复代码的相关部分:
unsigned int a = 10;
signed int b = -5;
printf("%d\n", a + b); /* 5 */
printf("%u\n", a + b); /* 5 */
在a + b
中,b
转换为无符号整数,(由无符号转换的规则产生UINT_MAX + 1 - 5
)。根据无符号算术的规则,将10加到该值的结果为5,其类型为unsigned int。在大多数情况下,C表达式的类型独立于其出现的上下文。 (请注意,这些都不取决于表示;转换和算术完全是根据数值定义的。)
对于第二个printf
调用,结果很简单:"%u"
期望类型为unsigned int
的参数,并且您已经给它一个。它会打印"5\n"
。
第一个printf
稍微复杂一些。 "%d"
期望类型int
的参数,但是您给它一个unsigned int
类型的参数。在大多数情况下,这样的类型不匹配会导致未定义的行为,但是有一个特殊情况规则,相应的有符号和无符号类型可以作为函数参数互换 - 只要该值在两种类型中都是可表示的(就像在这里一样) 。因此,第一个printf
也会打印"5\n"
。
同样,所有这些行为都是根据值而不是表示来定义的(除了要求给定值在相应的有符号和无符号类型中具有相同的表示形式)。你会在一个系统上得到相同的结果,其中signed int和unsigned int都是37位,signed int有7个填充位,unsigned int有11个填充位,而signed int使用1s'补码或符号和数量级表示。 (据我所知,现实生活中不存在这样的系统。)
答案 3 :(得分:1)
它被转换为unsigned
,无符号算术恰好给出你看到的结果。
无符号算术的结果相当于使用二进制补码进行带符号算术,并且没有超出范围的异常。