C语言中涉及无符号类型的对象的类型转换

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 :

我最近一直在阅读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 : %d\n",(unsigned)x);
}
#包括
int main()
{
有符号字符x=-1;
printf(“已签名:%d\n”,x);
printf(“未签名的:%d\n”,(未签名的)x);
}
  • 带符号的x位形式为:1000 0001=-1
  • 转换为无符号时,其值必须为1000 0001=129。 但即使在类型转换之后,它也会打印-1
注意:我使用的是gcc编译器


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
:(