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

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

特别是应该处理n==32值。

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

 ((uint32_t)1 << n) - 1 

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

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

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

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

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

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

 ~(~0 << n) 

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

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

或者:

 (n == 32) ? 0xFFFFFFFF : (((uint32_t)1 << n) - 1) 
 const uint32_t masks[33] = {0x0, 0x1, 0x3, 0x7 ... void setbits(uint32_t *x, int n) { *x |= masks[n]; } 

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

 -1 ^ ((1 << (32 - n)) - 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]; } } 

目标:

  • 没有分支(包括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); } 

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

  // 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  #include  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<= 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<= 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 <

  n: 1 << n (1<= 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”步骤都会完成。 然后,使用AND ffffffffn <= 0步骤也是noop。

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

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

具有简单测试的function:

 #include  #include  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; }