C语言:左移值带负号

时间:2013-08-22 17:14:19

标签: c

我对位移后的否定操作感到困惑。 例如:

-(1<<7) is 0xffffff80

但为什么最重要的位填充1? 我对操作-的含义感到困惑。

编辑1:我使用printf("%#08x\n", -(1<<7))打印出值。

5 个答案:

答案 0 :(得分:2)

首先,谢谢你提出这个问题。编写测试程序以说明您不确定的内容通常是个好主意,然后尝试不同的东西来弄清楚细节。

评论,就像UB一样,通常不准确。在这种情况下,所发生的事情是非常可预测和合理的,正是有经验的程序员应该期待的。

我在Eclipse / Microsoft C编译器上运行了以下代码:

#include <stdio.h>
main()
{
    int i;
    unsigned int j;

    i = -(1<<7);
    printf("%i\n", i);
    printf("%08x\n", i);

    j = -(1<<7);
    printf("%u\n", j);
    printf("%08x\n", j);
}

得到以下输出:

-128
ffffff80
4294967168
ffffff80

这是预期的,因为:(1 <7)等于128并且 - (128)是-128。 i的内容的printf完全以二进制形式生成了-128的值。

看到这个的方法是采用2的补码ffffff80 = 0000007f + 1 = 00000080,二进制为128。因此,您可以看到,取一个数的2的补码是我们如何取整数的负数。

真正的大数字是相同内容的无符号值。

尽可能写一些代码来检查内容是如何工作的!

答案 1 :(得分:0)

减号运算符(实现已定义,但最有可能)将在其参数上执行二进制补码(在本例中为十进制128)。 2的补码是:减1并反转所有位。

答案 2 :(得分:0)

有效位用1填充,因为它们代表符号,重复它们不会影响值。对于正数, 10 010 0000010 都是相等的。并且由于 1 的最重要位表示负数,因此在负数前面放置尽可能多的1并不会影响幅度。你可以使用2s补码算法检查这个事实。

答案 3 :(得分:0)

-(1<<7)不是0xffffff801<<7是第7次幂的1倍2,即128.所以-(1<<7)是-128。您将其视为0xffffff80的原因最可能的解释是,您通过将其传递给printf来调用未定义的行为,以便与%x格式说明符一起使用。 %x采用unsigned int参数(只要值为非负值,也可以采用带符号的int)但是您传递的参数类型为int,是否定的。因此,会导致未定义的行为。

答案 4 :(得分:0)

答案非常简单,其结果来自于如何在计算机内存中保存多个数字。

我猜你很明显1&lt;&lt; 7意味着。它等于128.你的“ - ”符号只表示你想改变结果的te符号,所以最终的结果是-128。

但为什么你会有所不同呢?这是答案:

通常有两种类型的变量:有符号和无符号。 两种类型都保存在momory中,实际上不知道哪种类型开始使用。程序员可以知道存储了哪种号码。

当您将变量声明为无符号时,它可以存储从0到n的值,其中n是特定类型变量的最大值。

使用带符号的值时,可以存储定义的负值中的值,直到某个定义的正值。

使用无符号变量时,计算值非常简单。 请考虑一个8位(1字节)无符号变量的简单示例:

如前所述,最小值为0,当设置了所有8位时,最大值为255.

对于签名类型的变量,正在使用特殊格式: 从0到127的数字的保存方式与无符号类型相同。并且127的值是8位变量的最大值。最小值为-128,存储为0b10000000或0x80。下一个是-127并保存为0b10000001或0x81,依此类推。最大的负数为-1,保存为0b11111111或0xFF。

因此,如果你有一个字节值0xff,它可以是:255(无符号时)或-1(有符号时)。 这里用于签名类型的变量的符号称为U2 - 请阅读此内容。

在您的特定情况下,您看起来有一个已签名(-128)的值,该值被视为无符号值。在你的情况下,使用32位(4字节)变量(可能(无符号)int),因此它看起来有点不同(结果更长),但你可能会看到一些相似性:U2中-128的最后两位数字无论用多少位来存储该值,系统总是为0x80。