2

可能重复:
如果我为无符号变量分配负值会发生什么?

我是 C++ 新手,我想知道如何使用无符号类型。对于unsigned int类型,我知道它可以取 0 到 4294967296 之间的值。但是当我想初始化一个 unsigned int 类型时,如下所示:

unsigned int x = -10;
cout << x;

输出看起来像4294967286 The got this output = max value - 10。所以我想了解内存中发生了什么?在此计算继续进行时,正在执行哪些过程?感谢您的回答。

4

3 回答 3

6

您遇到环绕行为。

无符号类型是循环的(另一方面,有符号类型可能是循环的,也可能不是循环的,但它是您不应该依赖的未定义行为)。也就是说,比最小可能值小一是最大可能值。您可以使用以下代码段自己演示这一点:

int main()
{
    unsigned int x = 5;
    for (int i = 0; i < 10; ++i) cout << x-- << endl;
    return 0;
}

您会注意到,在达到零后,x 的值会跳到 2^32-1,即最大可表示值。减去进一步的行为符合预期。

当您从无符号 0 中减去 1 时,位模式会以下列方式发生变化:

0000 0000 0000 0000 0000 0000 0000 0000 // before (0)
1111 1111 1111 1111 1111 1111 1111 1111 // after  (2^32 - 1)

对于无符号数,负数被视为从零减去的正数。所以(unsigned int) -10会相等((unsigned int) 0) - ((unsigned int) 10)

我喜欢将其视为无符号整数,它是高精度任意值的最低 32 位。像这样:

v imaginary high order bit
1 0000 0000 0000 0000 0000 0000 0000 0000 // before (2^32)
0 1111 1111 1111 1111 1111 1111 1111 1111 // after  (2^32 - 1)

在这些溢出情况下,unsigned int 的行为与从 256 中减去 1 时 unsigned int 的低 8 位的行为完全相同。像这样查看 unsigned char(1 字节)更有意义,因为如果转换为 0 和 256 值是相等的unsigned char,因为有限的精度会丢弃额外的位。

0 0000 0000 0000 0000 0000 0001 0000 0000 // before (256)
0 0000 0000 0000 0000 0000 0000 1111 1111 // before (255)

正如其他人指出的那样,这称为模运算。使用更高的精度值来帮助可视化环绕工作时所做的转换,因为您屏蔽了高阶位。它是什么并不重要,所以它可以是任何东西,它只是被丢弃。整数是超过模 2^32 的值,因此 2^32 的任何倍数在整数空间中都为零。这就是为什么我可以假装最后还有一点点。

模运算有自己的专用运算符,以防您需要在程序中为 2^32 以外的数字计算它们,如以下语句所示:

int forty_mod_twelve = 40 % 12;
// value is 4: 4 + n * 12 == 40 for some whole number n

对 2 的幂(如 2^32)的模运算直接简化为屏蔽高阶位,如果你取一个 64 位整数并以 2^32 为模计算,则该值将与转换后的值完全相同到一个无符号整数。

01011010 01011100 10000001 00001101 11111111 11111111 11111111 11111111 // before
00000000 00000000 00000000 00000000 11111111 11111111 11111111 11111111 // after

程序员喜欢使用这个属性来加速程序,因为很容易砍掉一些位数,但是执行模运算要困难得多(它和除法一样难)。

那有意义吗?

于 2012-10-08T17:40:23.723 回答
4

这涉及标准的积分转换。这是适用的规则。我们从字面量的类型开始10

2.14.2 整数文字 [lex.icon]

整数文字是没有句点或指数部分的数字序列。整数文字可能有一个指定其基数的前缀和一个指定其类型的后缀。数字序列的词汇第一个数字是最重要的。十进制整数文字(以十为基数)以除十进制数字之外的数字开头0并由十进制数字序列组成。八进制整数文字(以八为基数)以数字开头0,由一系列八进制数字组成。十六进制整数文字(以16 为基数)以0xor开头0X并由一系列十六进制数字组成,其中包括十进制数字和字母afAF十到十五的十进制值。[ 示例:数字十二可以写成120140XC。—结束示例]

整数文字的类型是表 6 中可以表示其值的相应列表中的第一个。

下面是一个表格,第一个类型是int并且它适合。所以文字的类型是int.

应用一元减号运算符,它不会更改类型。然后应用以下规则:

4.7 积分转换[conv.integral]

整数类型的纯右值可以转换为另一种整数类型的纯右值。无作用域枚举类型的纯右值可以转换为整数类型的纯右值。

如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2 n,其中 n 是用于表示无符号类型的位数)。[ 注意:在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。——尾注]

于 2012-10-08T17:34:02.697 回答
0

不要按你的方式打印值,而是以十六进制格式打印它(对不起,我忘记了如何用 cout 做到这一点,但我知道这是可能的)。您会看到这两个值的表示是相同的。

根据您的上下文,整数是 32 位(并非总是如此)。使用有符号整数时,最高有效位是符号,而不是值的一部分。使用无符号整数时,最高有效位是值的一部分。

于 2012-10-08T17:35:29.147 回答