Bitshifts取消而不是预期的行为

时间:2017-09-26 06:43:07

标签: c bit-manipulation bit bit-shift

我注意到使用括号进行位移的一些奇怪行为

 #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 ......最近怎么回事?这是未定义的吗?

5 个答案:

答案 0 :(得分:4)

char的位移会自动将其提升为int。这就是为什么7位的左移不能切掉任何东西的原因。

资料来源:the C standard

的第6.5.7节
  

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

答案 1 :(得分:2)

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

检查标准6.5.7 Bitwise shift operators必须说的内容:

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

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

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

  •   

答案 2 :(得分:1)

根据this online c standard draft,按位移位运算符将参数提升为整数类型:

  

6.5.7按位移位运算符

     

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

     

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

因此,当您编写 >>> pfync = {'average': 'mean()', 'maximin': 'max()', 'minimum': 'min()', 'Standard deviation': 'std()'} >>> opType=pfync['average'] >>> opType 'mean()' >>> 时,表达式c = (c << 7) >> 7中的c的值首先会转换为整数值,然后进行移位。因此,没有一个位丢失。将它们移回(c << 7)会得到原始值。

相反,当你写>> 7时,一旦将(整数)结果重新分配回d = (d << 7),这是一个无符号字符而不能保持“更高”的位,这些位就会丢失积分值。

答案 3 :(得分:1)

二进制表示中的

15310011001。按位移位运算符的操作数应具有类型int,否则将进行整数提升。

声明

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

c被提升为整数,假定整数表示为4个字节,c将为二进制00000000 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

答案 4 :(得分:0)

按照this comment的建议,我们会看一下在平台x86上为表达式class queryTest extends Controller { public function tableFetch() { $this->recursive(); } function recursive(){ //condition } } 生成的代码:

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) 的内容被加载到32位寄存器(c)中,并且在该寄存器上执行两个移位。最后,该寄存器的最低有效字节(即eax)被分配给变量al

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