将整数提升为long或unsigned long

时间:2015-05-14 21:04:21

标签: c types type-conversion

static uint32_t get_num(void);

uint32_t get_count(unsigned int mask)
{
  uint8_t i = 0;
  uint32_t count = 0;

  while (i < get_num())
  {
     if (mask & (1 << i++))
       count++;
  }

  return count;
}

在此代码中,哪些更安全(1L << i++)(1UL << i++)

2 个答案:

答案 0 :(得分:1)

无符号操作数更安全一点,因为只有这样才能在get_num()返回该操作数类型中的位数时定义的所有移位的行为。如果unsigned longunsigned int宽,那么ULU稍微安全一些,但仅适用于那些无效的get_num()结果。

然而,更安全的是:

uint32_t get_count(uint32_t mask)
{
  uint8_t num = get_num();

  if (num == 0) return 0;

  /* mask off the bits we don't want to count */
  mask &= ~((uint32_t) 0) >> ((num < 32) ? (32 - num) : 0);

  /* count the remaining 1 bits in mask, leaving the result in mask */
  mask = (mask & 0x55555555) + ((mask & 0xaaaaaaaa) >> 1);
  mask = (mask & 0x33333333) + ((mask & 0xcccccccc) >> 2);
  mask = (mask & 0x0f0f0f0f) + ((mask & 0xf0f0f0f0) >> 4);
  mask = (mask & 0x00ff00ff) + ((mask & 0xff00ff00) >> 8);
  mask = (mask & 0x0000ffff) + ((mask & 0xffff0000) >> 16);

  return mask;
}

答案 1 :(得分:0)

如果你只想计算uint中的1位并使用gcc,你应该看一下内置函数(这里:int __builtin_popcount (unsigned int x))。这些可以被高度优化,甚至可以使用CPU的特殊指令。 (一个人可以非常测试gcc)。

但是,不确定get_num()会产生什么 - 它似乎不依赖于mask,所以它的输出可以用来限制popcount的结果。

以下使用循环,并且可能比某些体系结构上的并行添加树更快(如果时间必要,则应该对两个版本进行分析)。

unsigned popcount(uint32_t value, unsigned width)
{
    unsigned cnt = 0;   // actual size intentionally by arch

    if ( width < 32 )
        value &= (1UL << width) - 1;  // limit to actual width

    for ( ; value ; value >>= 1 ) {
        cnt += value & 1U;    // avoids a branch
    }
    return cnt;
}

请注意,宽度将传递给函数。

在&lt;体系结构上32位(PIC,AVR,MSP430等)专用版本将获得比单个版本更好的结果。