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

时间:2011-11-14 21:50:43

标签: c++ c gcc bitwise-operators

如何(以最优雅的方式)设置n的最低有效位uint32_t?那就是写一个函数void setbits(uint32_t *x, int n);。函数应处理从n0的每个32

特别应该处理价值n==32

9 个答案:

答案 0 :(得分:20)

如果你的意思是最低n位:

((uint32_t)1 << n) - 1

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

n == 32 ? 0xffffffff : (1 << n) - 1

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

(uint32_t)(((uint64_t)1 << n) - 1)

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

答案 1 :(得分:16)

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

~(~0 << n)

答案 2 :(得分:10)

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

(uint32_t)(((uint64_t)1 << n) - 1)

可替换地:

(n == 32) ? 0xFFFFFFFF : (((uint32_t)1 << n) - 1)

答案 3 :(得分:5)

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

void setbits(uint32_t *x, int n)
{
   *x |= masks[n];
}

答案 4 :(得分:1)

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

-1 ^ ((1 << (32 - n)) - 1)

答案 5 :(得分:1)

如果n为零,则不应根据问题设置任何位。

const uint32_t masks[32] = {0x1, 0x3, 0x7, ..., 0xFFFFFFFF};

void setbits(uint32_t *x, int n)
{
    if ( (n > 0) && (n <= 32) )
    {
        *x |= masks[--n];
    }
}

答案 6 :(得分:1)

目标:

  • 没有分支(包括n的参数检查)
  • 没有64位转换
void setbits(uint32_t *x, unsigned n) {
    // As @underscore_d notes in the comments, this line is
    // produces Undefined Behavior for values of n greater than
    // 31(?). I'm ok with that, but if you're code needs to be
    // 100% defined or you're using some niche, little-used
    // compiler (perhaps for a microprocesser?), you should
    // use `if` statements. In fact, this code was just an
    // an experiment to see if we could do this in only 32-bits
    // and without any `if`s. 
    *x |= (uint32_t(1) << n) - 1;
    // For any n >= 32, set all bits. n must be unsigned
    *x |= -uint32_t(n>=32);
}

注意:如果您需要n类型int,请将其添加到结尾:

    // For any n<=0, clear all bits
    *x &= -uint32_t(n>0);

说明:

    *x |= -uint32_t(n>=32);

n>=32为真时,x将与0xFFFFFFFF进行按位或运算,产生x并设置所有位。

    *x &= -uint32_t(n>0);

此行指出,只要应设置任何位n>0,按位-AND x和0xFFFFFFFF,这将导致x无变化。如果n<=0,则x将与0进行按位与运算,从而导致值为0.

显示算法的示例程序:

#include <stdio.h>
#include <stdint.h>

void print_hex(int32_t n) {
  uint32_t x = (uint32_t(1) << n);
  printf("%3d:  %08x  |%08x  |%08x  &%08x\n",
         n, x, x - 1,
         -uint32_t(n>=32),
         -uint32_t(n>0));
}

void print_header() {
  //        1:  00000002  |00000001  |00000000  &ffffffff
  printf("  n:   1 << n    (1<<n)-1   n >= 32     n <= 0\n");
}

void print_line() {
  printf("---------------------------------------------\n");
}

int main() {
  print_header();
  print_line();
  for (int i=-2; i<35; i++) {
    print_hex(i);
    if (i == 0 || i == 31) {
      print_line();
    }
  }
  return 0;
}

输出(分解和注释):

对于n < = 0,最后一步与0结合,确保结果为0。

  n:   1 << n    (1<<n)-1   n >= 32     n <= 0
---------------------------------------------
 -2:  40000000  |3fffffff  |00000000  &00000000
 -1:  80000000  |7fffffff  |00000000  &00000000
  0:  00000001  |00000000  |00000000  &00000000

对于1 <= n <= 31,最后两步“OR 0,AND 0xffffffff”不会导致数字发生变化。唯一重要的一步是“OR(1&lt;

  n:   1 << n    (1<<n)-1   n >= 32     n <= 0
---------------------------------------------
  1:  00000002  |00000001  |00000000  &ffffffff
  2:  00000004  |00000003  |00000000  &ffffffff
  3:  00000008  |00000007  |00000000  &ffffffff
  4:  00000010  |0000000f  |00000000  &ffffffff
  5:  00000020  |0000001f  |00000000  &ffffffff
  6:  00000040  |0000003f  |00000000  &ffffffff
  7:  00000080  |0000007f  |00000000  &ffffffff
  8:  00000100  |000000ff  |00000000  &ffffffff
  9:  00000200  |000001ff  |00000000  &ffffffff
 10:  00000400  |000003ff  |00000000  &ffffffff
 11:  00000800  |000007ff  |00000000  &ffffffff
 12:  00001000  |00000fff  |00000000  &ffffffff
 13:  00002000  |00001fff  |00000000  &ffffffff
 14:  00004000  |00003fff  |00000000  &ffffffff
 15:  00008000  |00007fff  |00000000  &ffffffff
 16:  00010000  |0000ffff  |00000000  &ffffffff
 17:  00020000  |0001ffff  |00000000  &ffffffff
 18:  00040000  |0003ffff  |00000000  &ffffffff
 19:  00080000  |0007ffff  |00000000  &ffffffff
 20:  00100000  |000fffff  |00000000  &ffffffff
 21:  00200000  |001fffff  |00000000  &ffffffff
 22:  00400000  |003fffff  |00000000  &ffffffff
 23:  00800000  |007fffff  |00000000  &ffffffff
 24:  01000000  |00ffffff  |00000000  &ffffffff
 25:  02000000  |01ffffff  |00000000  &ffffffff
 26:  04000000  |03ffffff  |00000000  &ffffffff
 27:  08000000  |07ffffff  |00000000  &ffffffff
 28:  10000000  |0fffffff  |00000000  &ffffffff
 29:  20000000  |1fffffff  |00000000  &ffffffff
 30:  40000000  |3fffffff  |00000000  &ffffffff
 31:  80000000  |7fffffff  |00000000  &ffffffff

对于n >= 32,应设置所有位,并且无论前一步骤是做什么,“OR ffffffff”步骤都会完成。 n <= 0步骤也是AND ffffffff的noop。

  n:   1 << n    (1<<n)-1   n >= 32     n <= 0
---------------------------------------------
 32:  00000001  |00000000  |ffffffff  &ffffffff
 33:  00000002  |00000001  |ffffffff  &ffffffff
 34:  00000004  |00000003  |ffffffff  &ffffffff

答案 7 :(得分:1)

((((1 << (n - 1)) - 1) << 1) | 1)

设置最后n位。 n必须> 0.使用n = 32。

答案 8 :(得分:-1)

具有简单测试的功能:

#include <stdio.h>
#include <stdint.h>

void setbits(uint32_t *x, int n)
{
  *x |= 0xFFFFFFFF >> (32 - n);
}

int main()
{
  for (int n = 1; n <= 32; ++n)
  {
    uint32_t x = 0;
    setbits(&x, n);
    printf("%2d: 0x%08X\n", n, x);
  }
  getchar();
  return 0;
}