在unsigned int中设置最后的`n`位

Car*_*s00 13 c c++ gcc bitwise-operators

如何设置(以最优雅的方式)n最不重要的位uint32_t?那就是写一个函数void setbits(uint32_t *x, int n);.函数应该处理每一个n032.

尤其n==32应该处理价值.

Eri*_*ric 21

这是一个不需要任何算术的方法:

~(~0u << n)
Run Code Online (Sandbox Code Playgroud)

  • @DarkDust:除非这个(有时)因n = 32而失败,因为将`uint_32t`换成'32`是未定义的行为. (6认同)

Mar*_*tos 20

如果你的意思是最不重要的n位:

((uint32_t)1 << n) - 1
Run Code Online (Sandbox Code Playgroud)

在大多数体系结构中,如果n为32,这将不起作用,因此您可能需要为此做一个特殊情况:

n == 32 ? 0xffffffff : (1 << n) - 1
Run Code Online (Sandbox Code Playgroud)

在64位架构上,一个(可能)更快的解决方案是向下抛出:

(uint32_t)(((uint64_t)1 << n) - 1)
Run Code Online (Sandbox Code Playgroud)

实际上,这在32位架构上甚至可能更快,因为它避免了分支.

  • 那么n == 32呢? (2认同)
  • @TonyK:不,它不起作用,因为大多数架构都不支持将32位整数移位32位(当然不是英特尔). (2认同)
  • 右:"如果右操作数等于...提升左操作数的位长度,则行为未定义." [C++11§5.8/ 1] (2认同)
  • @MarceloCantos,IRC在32位整数上左移"31"导致溢出=>未定义的行为.然后`int`只能保证标准为16位宽.总之,对于从"16"到"31"的值,您的版本可能会失败. (2认同)
  • @MarceloCantos,同样在你的速度更快的版本中,将`n`转换为`uint64_t`的目的是什么?你应该"强制转换"`1`这就决定了表达式的类型. (2认同)

Oli*_*rth 10

其他答案不处理特殊情况n == 32(移动大于或等于类型的宽度是UB),所以这里有一个更好的答案:

(uint32_t)(((uint64_t)1 << n) - 1)
Run Code Online (Sandbox Code Playgroud)

或者:

(n == 32) ? 0xFFFFFFFF : (((uint32_t)1 << n) - 1)
Run Code Online (Sandbox Code Playgroud)

  • @Tony:不,他们没有.超出类型长度的移动是不确定的. (4认同)
  • @OliCharlesworth,铸造一个常数?这应该只是`UINT64_C(1)`。然后你的替代解决方案不适用于 16 位 `int` 的架构,但也不适用于 32 位 `int`,因为对于 `31` 你有溢出。 (2认同)

TJD*_*TJD 5

const uint32_t masks[33] = {0x0, 0x1, 0x3, 0x7 ...

void setbits(uint32_t *x, int n)
{
   *x |= masks[n];
}
Run Code Online (Sandbox Code Playgroud)