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++)
?
答案 0 :(得分:1)
无符号操作数更安全一点,因为只有这样才能在get_num()
返回该操作数类型中的位数时定义的所有移位的行为。如果unsigned long
比unsigned int
宽,那么UL
比U
稍微安全一些,但仅适用于那些无效的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等)专用版本将获得比单个版本更好的结果。