val*_*ldo 6 c bit-manipulation
我想我会疯了.
我有一段代码需要创建一个(无符号)整数,其N
后续位设置为1.确切地说,我有一个位掩码,在某些情况下,我想将它设置为一个实心的rnage.
我有以下功能:
void MaskAddRange(UINT& mask, UINT first, UINT count)
{
mask |= ((1 << count) - 1) << first;
}
Run Code Online (Sandbox Code Playgroud)
简单来说:1 << count
在二进制表示中100...000
(零的数量是count
),从这样的数字中减去1给出011...111
,然后我们只是左移它first
.
当满足以下明显限制时,上述结果应产生正确的结果:
first + count <= sizeof(UINT)*8 = 32
请注意,它也应该适用于"极端"情况.
count = 0
我们有(1 << count) = 1
,因此((1 << count) - 1) = 0
.count = 32
我们有(1 << count) = 0
,因为前导位溢出,并且根据C/C++规则,按位移位运算符不是循环的.然后((1 << count) - 1) = -1
(所有位设置).然而,事实证明,count = 32
公式不能按预期工作.如发现:
UINT n = 32;
UINT x = 1 << n;
// the value of x is 1
Run Code Online (Sandbox Code Playgroud)
而且,我正在使用MSVC2005 IDE.当我在调试器中评估上面的表达式时,结果为0.但是当我跳过上面的行时,x
得到值1.通过反汇编程序看到以下内容:
mov eax,1
mov ecx,dword ptr [ebp-0Ch] // ecx = n
shl eax,cl // eax <<= LOBYTE(ecx)
mov dword ptr [ebp-18h],eax // n = ecx
Run Code Online (Sandbox Code Playgroud)
确实没有魔法,编译器只使用了shl
指令.然后似乎shl
没有做我预期应该做的事情.CPU决定忽略此指令,或者将移位视为模32,或者不知道什么.
我的问题是:
shl
/ shr
指令的正确行为是什么?提前致谢
编辑:
谢谢你的回答.我已经意识到(1)shl
/ shr
确实对待操作数模32(或&0x1F)和(2)C/C++标准将移位超过31位视为未定义的行为.
然后我还有一个问题.我怎样才能重写我的"掩蔽"表达来覆盖这种极端情况.它应该没有分支(if
,?
).什么是最简单的表达方式?
oua*_*uah 12
1U << 32
当类型unsigned int
为32位宽时,在C和C++中是未定义的行为.
(C11,6.5.7p3)"如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义"
(C++ 11,5.8p1)"如果右操作数为负数,或大于或等于提升左操作数的位长度,则行为未定义."
归档时间: |
|
查看次数: |
4820 次 |
最近记录: |