2017-09-26 44 views
4

的,我注意到一些奇怪的行为与支架Bitshifts抵消,而不是预期的行为

bitshifting
#include <stdio.h> 

int  main(void) 
{ 
    unsigned char c; 
    unsigned char d; 

    c = 153; 
    c = (c << 7) >> 7; 
    printf("%d\n", c); 
    d = 153; 
    d = (d << 7); 
    d = (d >> 7); 
    printf("%d\n", d); 
} 

输出:

153 
1 

我预计c也有1 ...值怎么回事上?这是不确定的?

+2

看看生成的代码以及它的功能。 –

+1

与[this]类似(https://stackoverflow.com/questions/33068985/sizeof-an-integer-expression-in-c)问题。表达式被评估为一个整数,然后存储为char。与中间步骤中的字符对比。 – matt

+0

没问题,lemmi只能使用类型转换 –

回答

4

位移char自动将其升级到int。这就是为什么7位左移不能切断任何东西。

来源:the C standard

部6.5.7整数优惠在每个操作数的执行。结果的类型是 升级左操作数的类型。如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。

+1

不错的答案,比我快,+ 1 – gsamaras

+0

耶谢谢。我现在也选择使用'c =(unsigned char)(c << 7) >> 7;'它给了我预期的输出 –

2

它被评估为int,然后存储为char。并且在中间步骤不是char。换句话说,当你移位char时,它会被提升为int

检查什么标准6.5.7 Bitwise shift operators有说:

  • 的整数促销活动在每个操作数的执行。

  • 结果的类型是提升的左操作数的类型。

  • 如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为为 未定义。

0

按照什么this comment表明,我们来看看这是对平台的x86生成表达c = (c << 7) >> 7代码:

movzbl 31(%esp), %eax ;eax = c 
sall $7, %eax ;left shift 
sarl $7, %eax ;right shift 
movb %al, 31(%esp) ;c = al (one byte) 

c内容被加载到32 (eax),并且这两个移位都在该寄存器上执行。最后,该寄存器的最低有效字节(即al)被分配给变量c

简而言之,两个移位都被评估为操作数是32位宽。

1

根据this online c standard draft,按位移位运算促进参数为整数类型:

6.5。7位移位运算符

2每个操作数应具有整数类型。

3对每个操作数执行整数提升。

所以当你写c = (c << 7) >> 7,的c在表达(c << 7)的值首先被转换为一个整数值,然后移动。因此,没有一点会迷失。将它们移回>> 7给出原始值。

当您编写d = (d << 7)时,相反,一旦将(积分)结果重新分配给d(这是一个无符号字符并且因此无法保持整数值的“高位”位),位会丢失。

1

153 in binary representation is 10011001。按位移操作符的操作数应该有int类型,否则将发生整数提升。

For语句

c = (c << 7) >> 7; 

c被促进为整数,并假设为整数表示4个字节,c00000000 00000000 00000000 10011001二进制。所以表达式

c = (c << 7) >> 7; // Left and right shift operator will nullify the effect of each other. 

将有表达

c = c; 

的效果在

d = (d << 7); 
d = (d >> 7); 

情况下,第一条语句d后会有值(二进制)10000000。在第二个陈述后d将有值(二进制)00000001