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 次 |
| 最近记录: |