C 混合有符号整数和无符号整数的不合理行为

C 混合有符号整数和无符号整数的不合理行为,c,unsigned-integer,integer-promotion,signed-integer,C,Unsigned Integer,Integer Promotion,Signed Integer,受下面一段代码片段的启发,“当我混合使用有符号和无符号整数时会发生什么?”我决定使用几个不同的有符号和无符号整数值来运行它,并观察其行为 这是原始代码段(稍作修改,但意图仍然相同) #包括 内部主(空) { 无符号整数a=6; int b=-20; int c=(a+b>6); 无符号整数d=a+b; printf(“”,c,d); } 输出: 现在,当我为a=6和b=-1运行相同的程序时 输出: 如果我正确理解了C语言的规则,b=-1应该被提升为无符号整数,这将使它成为4294967295。

下面一段代码片段的启发,“当我混合使用有符号和无符号整数时会发生什么?”我决定使用几个不同的有符号和无符号整数值来运行它,并观察其行为

这是原始代码段(稍作修改,但意图仍然相同)

#包括
内部主(空)
{
无符号整数a=6;
int b=-20;
int c=(a+b>6);
无符号整数d=a+b;
printf(“”,c,d);
}
输出:

现在,当我为
a=6
b=-1
运行相同的程序时

输出:

如果我正确理解了C语言的规则,
b=-1
应该被提升为无符号整数,这将使它成为
4294967295
。就像原始示例一样,我们应该得到
。但这不是我们得到的

我能想到的这种行为的唯一原因是这些隐式类型转换发生在算术运算之后。然而,同一篇博文还说,有符号整数首先被提升,然后进行求值,这使我的推理无效

这种行为的真正原因是什么?以及这两个例子的不同之处



p.S我知道SO上有许多问题与此问题类似/相关。但我并没有遇到任何特别解决这个问题的问题,也并没有遇到任何有助于理解这些代码片段的问题。如果发现是重复的,我很乐意接受这个问题

因此您需要
4294967301
,但这不适合32位无符号整数,因为最大值为
2^32-1
4294967295
。因此
4294967295
等于
0xFFFFFFFF
。带
0xFFFFFF+6
的是
0x00000005
。当有符号整数从
2147483647
0x7FFFFFFF
)滚动到
-2147483648
0x8000000
)时,称为溢出。当无符号从
4294967295
0xffffff
)滚动到
0
0x00000000
)时,它是一个环绕

 /*unsigned*/a+/*signed*/b
b
将由于以下原因转换为
未签名的

转换将由完成,对于
unsigned==uint32\u t
而言,这意味着添加
2^32
(一次)

如需参考,其中
无符号==uint32\u t

UINT_MAX+1 == 2^32 == 4294967296
对于
(未生成)a==6
(已签名)b==-20
,您可以得到:

2^32-20 + 6 == 4294967282  (<= UINT_MAX)
2^32-1 + 6 == 4294967301 (>UINT_MAX)
现在,因为这个结果大于
UINT_MAX
,所以它将被包装成
5
(通过减去
UINT_MAX+1
,可以得到这个值,它是如何定义包装的())


在two的补码体系结构上,这些规则基本上转化为一个简单的
add
,这意味着您也可以使用有符号表示(
6-20==-14;6-1==5
)来执行该操作,然后将结果重新解释为
unsigned
(在第二种情况下,似乎是获取5的更直接的方法,不是吗),但了解规则仍然很好,因为C(C!=assembly)中未定义有符号溢出,这给了您的编译器很大的余地,可以将代码转换为您在假设直接的C到汇编映射时无法预料的内容。

我不明白问题是什么。对我来说,这一切似乎都是合理的行为。是不是在6,-20的情况下,
C
应该是
0
?第一个输出基本上是第二个输出是“6以上为5,然后为1,否则为0,然后为5”“。你的问题是什么?让我总结一下。是的,4294967282大于6,然后是1。不,5不是大于6,然后是0。你的问题是什么?请记住,如果你加上两个数字,a+b,其中a是无符号的,b是有符号的,那么“它将正确计算”如果您只是根据位的含义将有符号值重新解释为无符号值。
?1:0
是不必要的。
运算符生成类型为
int
1
如果条件为真,则生成类型为假的结果。
0
从技术上讲(如在中,根据C标准),这不是溢出。溢出只能发生在有符号的类型上。谢谢!我在谷歌上疯狂搜索,试图确认它是否真的被称为溢出。哦,对了。当无符号整数溢出时,它只是被称为进位。虽然我不知道进位是否在C中公开。修复了解释差异的注释!@Tinythebrotonosaurus:不是被称为“进位”,至少不符合C标准。常用的术语是“环绕”“环绕”是贯穿这一过程的关键。我想这个可怕的数字4294967301让我很难看出它超出了范围。谢谢你最后一段,这段话从我提出的怀疑推理中是有意义的。顺便问一下,有没有一个简单的例子,你可以分享一下,我们比UINT_MAX多“减去”一个来做c型onversion?我的意思是,我们什么时候才能真正为类型转换进行减法运算?@Prateek,例如,最后一段代码,其中4294967301被转换为5。但这只是一个换行,对吗?一个超出范围的无符号加法被换行了。我认为那里没有发生任何数据类型的转换。@Pratek它的工作原理是一样的。
uint64\ta=4294967301UL;uint32_t b=a;
这里通过减去
uint32_MAX+1
得到了一个真正的64位4294967301,它被转换到
(uint32_t)5