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

时间:2018-08-31 05:54:41

标签: c type-conversion

我最近一直在阅读KnR,并遇到一条声明:

  

“涉及无符号类型值的表达式的类型转换为   复杂”

因此,为了理解这一点,我编写了一个非常小的代码:

#include<stdio.h>
int main()
{
    signed char x = -1;
    printf("Signed : %d\n",x);
    printf("Unsigned : %d\n",(unsigned)x);
}
  • 带符号的x位格式为:1000 0001 = -1
  • 当转换为无符号时,其值必须为1000 0001 = 129。 但是即使在类型转换之后,它也会打印-1。
  

注意:我正在使用gcc编译器。

2 个答案:

答案 0 :(得分:0)

C11 6.3.1.3,第2段:

  

否则,如果新类型为 unsigned ,则该值将转换为   重复加或减一个比最大值大   可以用新类型表示,直到该值在   新类型。

−1不能表示为unsigned int值,-1转换为UINT_MAX。因此-1变成一个非常大的正整数。

另外,对%u使用unsigned int,否则结果将调用未定义的行为。

答案 1 :(得分:0)

关于整数转换的语义是根据数学值而不是根据位定义的。最好了解值如何表示为位,但是在分析表达式时,您应该考虑值。

在此声明中:

printf("Signed : %d\n",x);

signed char x自动升级为int。由于x为-1,因此新的int的值也为-1,并且printf会打印“ -1”。

在此声明中:

printf("Unsigned : %d\n",(unsigned)x);

signed char x自动升级为int。该值仍为-1。然后,强制转换将其转换为unsigned。转换为unsigned的规则是,将UINT_MAX+1添加到值中或从中减去,以使其进入unsigned的范围内。在这种情况下,将UINT_MAX+1添加到−1一次会将值带到UINT_MAX,在范围之内。因此转换结果为UINT_MAX

但是,然后将此unsigned值传递到printf,以进行%d转换打印。这违反了C 2018 7.21.6.1 9,该法律指出,如果类型不匹配,则行为未定义。

这意味着C实现可以执行任何操作。在您的情况下,似乎发生了什么:

  • unsignedUINT_MAX用一位表示。
  • printf将所有一位的值解释为int
  • 您的实现对int类型使用两个补码。
  • 以两位数的补码表示,一个全为1的对象表示-1。
  • 所以printf印有“ -1”。

如果您使用的是正确的代码,则:

    printf("Unsigned : %u\n",(unsigned)x);

然后,printf将打印UINT_MAX的值,该值可能为4,294,967,295,因此printf将打印“ 4294967295”。