int上的左移操作

时间:2016-03-17 08:14:06

标签: c bit-manipulation

在IndiaBix.com上,我遇到了以下问题。根据我的经验水平(C语言中的初学者),上面的输出应该是0 (10000000 << 1 is 00000000),但是在经过更深入的我发现后,它的结果为256我们使用%d 打印,支持4个字节,因此输出为256而不是0。

#include<stdio.h> 
    int main()
    {
        unsigned char i = 128;
        printf("%d \n", i << 1);
        return 0;
    }

现在考虑以下示例

#include<stdio.h>

int main()
{
    unsigned int i = 2147483648;(bit 31 = 1 and b0 to b30 are 0)
    printf("%d \n", i<<1);
    return 0;
}

当我离开上面时,我得到0作为输出,因为%d支持int的值,输出应该是0但是当我将%d更改为%ld时输出仍为0.因为%ld支持值长达int输出不应该是0.为什么我得到0作为输出。

5 个答案:

答案 0 :(得分:2)

在第一种情况下,i被提升为int,可以存储至少32767,然后计算移位。结果,结果变为256。

在第二种情况下,如果您的unsigned int长度为32位,则会在unsigned int中计算,结果将会结束。结果,结果变为0。

你必须投射到更大的类型才能得到你想要的东西。

#include<stdio.h>
#include<inttypes.h>

int main()
{
    unsigned int i = 2147483648;//(bit 31 = 1 and b0 to b30 are 0)
    printf("%"PRIu64" \n", (uint64_t)i<<1);
    return 0;
}

答案 1 :(得分:2)

此处不重要%d%ld

可能是因为机器上的大小为unsigned int ,只有4个字节。

此外,您不能将%ld unsigned int 一起使用。这是未定义的行为。

答案 2 :(得分:1)

第一个问题是2147483648(80000000h)将适合您的32位无符号整数,但它不适合printf在使用int说明符时所期望的签名%d。相反,请使用%u说明符。

修复后,请注意,如果unsigned int为32位,0x80000000 << 1 假设为0。

printf的格式说明符更改为%ld不会更改表达式的类型!如果需要更大的类型,则需要更改两者格式说明符表达式。

你被第一个char印刷品的行为所欺骗。 %d在那里工作的原因是因为printf(像任何可变函数一样)在内部将所有参数提升为至少int的大小。因此,表达式被隐式提升为int,并且恰好与%d匹配。

虽然在my_char << n的情况下,<<运算符已经整数将两个操作数提升为int,并且移位的结果始终具有可能提升的左操作数的类型。 / p>

正如您所知,C中的各种隐式类型提升规则并非易事,因此可以轻松地创建错误。这是该语言众多众所周知的缺陷之一。

答案 3 :(得分:0)

根据C标准(6.5.7按位移位算子)

  

3 对每个操作数执行整数提升。   结果的类型是提升的左操作数....

和(6.3.1.1布尔,字符和整数)

  
      
  1. ...如果int可以表示原始类型的所有值(按宽度限制&gt;对于位字段),该值将转换为   一个int;否则,它将转换为unsigned int。 这些是   称为整数提升 .58)所有其他类型均未更改   整数促销。
  2.   

这意味着类型unsigned char的操作数被提升为int类型,因为类型int可以表示unsigned char类型的所有值。

所以在表达中

i << 1

操作数i被提升为类型int,你会得到(假设int类型有32位)

0x00000080 << 1

手术后你会得到结果

0x00000100

对应十进制

256

和本声明

printf("%d \n", i << 1);

输出此结果。

现在考虑一下这段代码

unsigned int i = 2147483648;(bit 31 = 1 and b0 to b30 are 0)
printf("%d \n", i<<1);

此处i可以表示为

0x80000000

整数提升适用于转换级别小于int类型的类型。

因此整数促销不会应用于变量i,因为它的排名不会低于int的等级。

操作完成后,您将获得

0x00000000

即你将得到十进制

0

和本声明

printf("%d \n", i<<1);

将正确输出此零,因为它的表示对于无符号和有符号整数对象是相同的。

即使你写了例如

printf( "%lld \n", ( long long int )( i<<1 ));

你会得到相同的结果,因为在任何情况下表达式i << 1的类型都是unsigned int

但是如果你要写

printf( "%lld \n", ( long long int )i << 1 );

然后操作数i将转换为long long int类型,您将获得

0x0100000000

答案 4 :(得分:0)

将%d更改为%id无效 将数据类型更改为unsigned,这将有助于您增加整数限制