C中的无符号和有符号值(输出)

C中的无符号和有符号值(输出),c,unsigned,signed,C,Unsigned,Signed,y的值是多少?这是怎么回事?y=0xfffffffb 它是-5(二的补码)的二进制表示形式。它取决于无符号整数的最大值。通常,unsigned int的长度为32位,因此UINT\u MAX的长度为232位− 1.C标准(§6.3.1.3/2)要求签署→ 无符号转换可以按如下方式执行: 否则,如果新类型是无符号的,则会通过重复地将新类型中可以表示的最大值加上或减去一个值来转换该值,直到该值在新类型的范围内 因此y=x+((232− 1) + 1) = 232 − 5=4294967291 在当

y
的值是多少?这是怎么回事?

y=0xfffffffb
它是-5(二的补码)的二进制表示形式。它取决于无符号整数的最大值。通常,
unsigned int
的长度为32位,因此
UINT\u MAX
的长度为232位− 1.C标准(§6.3.1.3/2)要求签署→ 无符号转换可以按如下方式执行:

否则,如果新类型是无符号的,则会通过重复地将新类型中可以表示的最大值加上或减去一个值来转换该值,直到该值在新类型的范围内

因此y=x+((232− 1) + 1) = 232 − 5=4294967291


在当今大多数实现都使用的平台中,
y
也与
x
的2的补码表示相同


-5=~5+1=0xFFFFFA+1=0xFFFFFB=4294967291。

y的值为
UINT_MAX-5+1
,即
UINT_MAX-4

将有符号整数值转换为无符号类型时,该值将以2^N的模减少,其中N是无符号类型中形成值的位数。这适用于正负符号值

如果要从相同大小的有符号类型转换为无符号类型,则上述表示正有符号值保持不变(
+5
转换为
5
),负值添加到
MAX+1
,其中
MAX
是无符号类型的最大值(
-5
转换为
MAX+1-5
)。

来自C99标准:

6.3.1.3有符号和无符号整数

  • 将整数类型的值转换为其他整数类型时 除_Bool外,如果 该值可以由新类型表示,但保持不变
  • 否则,如果新类型是无符号的,则该值将由 反复添加或 比可以表示的最大值多减去一个 新型 直到值在新类型的范围内。 (49)
  • 49)规则描述的是基于数学值的算术运算,而不是给定类型表达式的值

    因此,您将有效地看到,
    y=x+UINT\u MAX+1


    这恰好意味着twos补码表示法作为无符号整数使用,这使得大多数现代计算机的运算速度非常快,因为它们使用twos补码表示有符号整数。

    有符号值通常存储为一种称为:

    二的补码是将负数编码成普通二进制的一种方法,这样加法仍然有效。加-1+1应该等于0,但普通加法的结果是2或-2,除非运算特别注意符号位并执行减法。2的补码在没有额外步骤的情况下得到正确的和

    这意味着内存中数字-5和4294967291(对于32位字)的实际表示是相同的,例如:
    0xFFFFFFFB
    0b11111111111111011
    。所以当你这样做的时候:

    signed int x = -5;
    unsigned int y = x;
    
    x的内容逐字复制,即按位复制到
    y
    。这意味着,如果检查
    x
    y
    内存中的原始值,它们将是相同的。但是,如果您这样做:

    unsigned int y = x;
    
    x
    的值在转换为无符号long之前将进行符号扩展。在long long为64位的常见情况下,这意味着
    y1
    等于
    0xfffffffffffb

    重要的是要注意当铸造到较大的类型时会发生什么。转换为较大有符号值的有符号值将进行符号扩展。如果源值是无符号的,则不会发生这种情况,例如:

    unsigned long long y1 = x;
    
    z
    z1
    将等于0,但
    z2
    将不等于0。这可以通过在展开之前将值强制转换为signed来解决:

    unsigned int z = y + 5;
    long long z1 = (long long)x + 5; // sign extended since x is signed
    long long z2 = (long long)y + 5; // not sign extended since y is unsigned
    
    或者类似地,如果您不希望出现符号扩展:

    long long z3 = (long long)(signed int)y + 5;
    

    当您尝试此操作时,您看到了什么?@KennyTM,未定义实现;从一个无符号整数到一个不能表示它的有符号整数的强制转换是实现定义的,但另一种方式(有符号->无符号)是定义良好的。@bdonlan:
    UINT\u MAX
    是实现定义的。@KennyTM:请修复严重错误的注释。我不敢相信它居然获得了3票以上的选票。史蒂夫·杰索普:根据标准,答案是UINT_MAX-4。UINT_MAX是实现定义的。有一个直截了当的答案,但数字答案是实现定义的。结果不依赖于任何“二进制表示”。结果取决于语言标准的要求。在这种情况下,标准相当明确。@AndreyT。公平地说,虽然它不是这样表述的,但肯定的是,2的补语->未签名的转换结果以相同的位模式(我认为C++标准提到了这一点,不记得C标准是否)。Philibert的描述相当于标准中的定义:通过计算有符号值的2的补码表示,然后将其作为无符号值读取,可以转换为有符号->无符号。他从未说过实现实际上就是这样做的(尽管毫无疑问2的补充实现确实是这样)。@Steve Jessop:好吧,它并不等同于标准中的定义,至少因为标准定义不限于相同大小的类型之间的转换,而“同一表示法”这种方法只适用于大小相同的情况。@AndreyT:true,它只适用于被询问的案例,它根本不适用于其他案例。我更担心
    int
    是32位的假设。您缺少一个:UINT\u MAX是2^N-1。这不完全正确。正确的公式是
    y=x+UINT\u MAX-1long long z4 = (long long)(unsigned int)x;