我有一个小的正整数n
,我使用一个无符号整数类型来存储一个包含n
位的掩码。通常,需要构造具有所有n
位集的掩码。例如,如果n
是5,则掩码将是0b11111u
。
构造这种掩码的典型方法是执行以下操作(本示例假设掩码使用unsigned
,但可以为任何无符号整数类型编写一些内容):
unsigned all_set_mask = (1u << n) - 1u;
然而,如果n
正好等于无符号整数类型的位宽,则1u << n
是未定义的行为,如[expr.shift#1]所示:
操作数应为整数或无作用域枚举类型,并执行整数提升。结果的类型是提升的左操作数的类型。如果右操作数为负,或大于或等于提升的左操作数的宽度,则行为未定义。
合理的解释“构造一个掩码,设置所有n
位”可以说应该允许这样的情况,即我们的位数正好与底层整数类型的位宽一样多,因此典型的实现不支持所有合理的输入。
此外,在现代处理器上,汇编左移指令在移位位宽时是无操作的,因此all_set_mask
可能最终成为0
,这在任何情况下都不是预期的答案。
有没有一种符合标准的方法来重写它,而不需要求助于if
语句或复杂的位操作?我查看了<bit>
,但没有看到任何有用的东西。
4条答案
按热度按时间t98cgbkg1#
一个简单的方法如下:
我们可以稍微重写一下,以在移位计数取寄存器宽度取模的典型架构上保存一条指令:
然后去掉条件:
这应该在典型的CPU上编译为三条指令(汇编比C更可读的罕见情况之一)。
请注意,这假设有符号右移是算术移位,只有从C20开始它才是迂腐的正确。
nmpmafwu2#
我建议设置所有的位和右移走不需要的位。
当
n
是0
时,您仍然需要测试边缘情况,否则它将移走所有位,结果是未定义的行为。Demo
yc0p9oo03#
你可以对任何unsigned类型无条件地执行此操作:
使用16位无符号的示例:
vfh0ocws4#
在x86 - 64上,
_bextr_u64(UINT64_C(-1), 0, n)
。