我注意到使用括号进行位移的一些奇怪行为
#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 ......最近怎么回事?这是未定义的吗?
答案 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)
153
为10011001
。按位移位运算符的操作数应具有类型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位宽。