2012-03-25 79 views
0

Following my previous question,我需要创建包括设置为1的位的固体范围的值I中使用下列的函数:设置一个位范围中的序

void MaskAddRange(UINT& mask, UINT first, UINT count) 
{ 
    mask |= ((1 << count) - 1) << first; 
} 

然而,如发现,它没” t对于count = 32正确工作。的1 << count在这样的情况下结果理论上是未定义的行为(或结果),和几乎在x86是1,因为换档操作数处理的模数为32

欲解决这个表达式为正常工作这个极端的例子也是。什么是最简单/很好/有效的方式来做到这一点?

通过分支(if,?)处理这个特定的情况虽然很丑,但有点简单,我敢打赌它也是低效的。

另一种方法是将移位操作数提升为更大类型(64位)。我的意思是:

void MaskAddRange(UINT& mask, UINT first, UINT count) 
{ 
    mask |= (UINT(unsigned __int64(1) << count) - 1) << first; 
} 

有没有更好的方法?

+0

为什么不使用'UINT(-1)'? – 2012-03-25 14:24:33

+0

@Kerrek SB:怎么样? – valdo 2012-03-25 14:26:08

+0

嗯。你可以添加一个简单的,简短的简要描述你的函数所需的行为吗?我不希望从有问题的代码中反向设计需求。 – 2012-03-25 14:27:40

回答

1

永远不要假设任何事情都是无效的,除非你能证明它。在升级到64位时,if-else可能更适合您的架构+操作系统。我认为除了你已经发布的那两个以外,还有其他任何理智的方法。

我会去if-else,因为它文件处理极端情况的意图。升级到64位并不表示该意图。

+0

非常感谢您撰写高效软件指南的理论文章。但是在我的特殊情况下,我可以很容易地证明分支比单个CPU指令的效率低(已经这样做)。我也相信,一种理智的方法应该根据“受过教育的猜测”假设一些事实,然后进行强制性验证。 – valdo 2012-03-25 14:43:47

+0

P.S.我同意使用明确的“if-else”实际上自我记录了处理特定极端情况的意图,这有些有价值。更一般地说,OTOH我更喜欢写一些内在涵盖所有极端情况的东西(如果可以的话)。然后,更容易看到程序流程,而不需要在思维上考虑所有情况。这通常也会导致更好更通用的表述。 – valdo 2012-03-25 14:53:03

+0

您能否向我们提供您所指的“单CPU指令”?因为你的(或霍华德)功能永远不会是单一的指令,我可以保证。但是为了简化讨论,让我这么说:在一个支持64位整数运算的CPU上,你的64位升级代码将是最有效的。看到你如何使用Windows,你可能运行在一个支持64位整数操作的CPU上。 – Irfy 2012-03-25 15:14:06

0

您可以使用

mask |= (UINT(-1)<<first) & (UINT(-1)>>(32-first-count)) 

这是比较复杂的,但应该在任何情况下工作。这个表达式相对于其他解决方案的效率可能取决于体系结构和编译器。

+0

有趣。然而,它很容易出现另一种极端情况,其中'first = 0'和'count = 0'。 – valdo 2012-03-25 14:46:36