C语言中涉及无符号类型的对象的类型转换
我最近一直在阅读KnR,并遇到一个声明:C语言中涉及无符号类型的对象的类型转换,c,type-conversion,C,Type Conversion,我最近一直在阅读KnR,并遇到一个声明: printf("Signed : %d\n",x); printf("Unsigned : %d\n",(unsigned)x); “涉及无符号类型值的表达式的类型转换是 复杂的” 为了理解这一点,我编写了一个非常小的代码: #include<stdio.h> int main() { signed char x = -1; printf("Signed : %d\n",x); printf("Unsigned :
printf("Signed : %d\n",x);
printf("Unsigned : %d\n",(unsigned)x);
“涉及无符号类型值的表达式的类型转换是
复杂的”
为了理解这一点,我编写了一个非常小的代码:
#include<stdio.h>
int main()
{
signed char x = -1;
printf("Signed : %d\n",x);
printf("Unsigned : %d\n",(unsigned)x);
}
#包括
int main()
{
有符号字符x=-1;
printf(“已签名:%d\n”,x);
printf(“未签名的:%d\n”,(未签名的)x);
}
- 带符号的x位形式为:1000 0001=-1
- 转换为无符号时,其值必须为1000 0001=129。 但即使在类型转换之后,它也会打印-1
C116.3.1.3,第2段: 否则,如果新类型为无符号,则该值将通过 重复地加上或减去一个大于最大值 可以在新类型中表示,直到值在 新型的
−1
不能表示为无符号整数
值−1转换为UINT\u MAX
。因此,-1
成为一个非常大的正整数
另外,对无符号整数使用
%u
,否则结果调用未定义的行为。C有关整数转换的语义是根据数学值定义的,而不是根据位定义的。理解值是如何表示为位是很好的,但是,在分析表达式时,您应该考虑值
在本声明中:
printf("Signed : %d\n",x);
printf("Unsigned : %d\n",(unsigned)x);
signed char
x
自动升级为int
。因为x
是−1,新的int
也具有该值−1和printf
prints“-1”
在本声明中:
printf("Signed : %d\n",x);
printf("Unsigned : %d\n",(unsigned)x);
signed char
x
自动升级为int
。该值仍然为零−1.然后,强制转换将其转换为无符号的。转换为无符号
的规则是根据需要将UINT_MAX+1
添加到值或从值中减去,以使其进入无符号
的范围。在这种情况下,将UINT_MAX+1
添加到−1一旦将值带到范围内的UINT\u MAX
。因此,转换的结果是UINT\u MAX
但是,该无符号
值随后被传递到printf
,以使用%d
转换进行打印。这违反了C 2018 7.21.6.19,该条款规定,如果类型不匹配,则行为未定义
这意味着C实现可以做任何事情。在您的情况下,似乎发生了以下情况:
无符号
值UINT\u MAX
用所有一位表示
printf
将所有一位值解释为int
- 您的实现对
int
类型使用两个补码
- 在二的补码中,所有一位的对象表示−一,
- 所以
printf
printed“-1”
如果您使用了正确的代码:
printf("Unsigned : %u\n",(unsigned)x);
然后printf
将打印UINT_MAX
的值,该值很可能是4294967295,因此printf
将打印“4294967295”。此行为相当无趣,因为%d
意味着“将传递给printf的任何内容都视为有符号的int”。此外,由于printf是可变函数,如果参数是小类型,则传递的参数会隐式升级为int
。个人建议:用火烧掉K&R,然后阅读。@Lundin,然后承认这是个坏主意,再购买两份副本以防再次判断失误;-)@如果你愿意,我们可以玩一个游戏,你可以在K&R中随机选择一个页面。如果我发现任何打字错误、不正确的语句、对定义不好的行为的依赖或公然违反C编程事实上的良好实践,我们会烧掉该页面。你要保留剩下的东西。尽管如此,甚至连封面都不会保留…@Bathsheba唉,提到兰德(rand)
(第43页)的页面中包含了“强制转换运算符与其他一元运算符具有相同的高优先级,如本章末尾的表中所总结的那样”,这显然是不正确的,并且指向了同样不正确的优先级表。请参阅C17 6.5.4语法:强制转换表达式:一元表达式(类型名称)强制转换表达式
。C90也是如此,所以这本书早在1989年就不正确了。现在我烧掉了包含这些误导信息的页面,因此我们不能使用rand
:(