【问题标题】:How to efficiently extract the bit position as a value in C如何有效地将位位置提取为C中的值
【发布时间】:2021-02-17 22:03:57
【问题描述】:

我正在寻找一种有效的(最好是宏)方法来提取位的位置并将其保存为 C 中的值。

data = 0x4000

会产生:

pos = 14

我正在读取的 16 位寄存器中只会设置一个位。目前,我只是将数据与位移值进行比较以提取位置,但一定有更好的方法我不知道。

我花了一些时间在这里搜索一个类似的问题,但找不到。

【问题讨论】:

  • 这是一个16位的值?编写一个switch 语句,标识设置了 16 位中的哪一个。
  • 要么选择 Switch Case,要么选择带面具的循环 (data & (1<<n))
  • 你真正想要达到什么目的?看起来你想在这里的圆孔里放一个方钉(xy 问题)
  • 您是否针对特定的编译器?如果是这样,可能有一个内置函数可以使用。
  • 如果 i.E.数据 = 0x807f?

标签: c bit-manipulation c-preprocessor


【解决方案1】:

现代处理器只有一条指令来执行此操作(计算尾随零、查找第一个集合、计算前导零和查找最后一个集合)。在 gcc 和 clang 中,__builtin_ctz(n) 将返回数字中尾随零的数量。在支持单指令 ctz 的处理器上,它编译为一条指令。确保使用足够宽的函数(即__builtin_ctz 用于int 或更窄,__builtin_ctzl 用于long int 或更窄,或__builtin_ctzll 用于long long int 或更窄。对于16 位寄存器,__builtin_ctz应该足够了。

请参阅gcc documentationwikipedia 了解更多信息。

【讨论】:

  • 这正是我一直在寻找的原因。谢谢。
【解决方案2】:

与平台无关的解决方案是最便携和最有效的解决方案,但它也很悲观;许多现代处理器都有这样的位操作指令和内在函数。

例如,x86-64 具有 bsf 指令,该指令将使用另一个操作数中最高有效设置位的位置填充一个操作数:

bsf eax, 0x00004000
; eax now holds the value '14'

但是,“纯”C 解决方案看起来像:

int MSBPos = 0;
while(data && !(data & 1)) // 'data' check avoids infinite loop if data is 0
{
    MSBPos++;
    data >>= 1;
}

注意,这仅适用于 OP 的情况,即他保证整个值中有一个设置位,而所有其他位均为 0。

不过,我不会担心它是线性算法;位操作非常快。

【讨论】:

  • 赞成一个好的答案。 __builtin_ctzl() 易于使用,只需 3 条指令即可完成任务。 2个动作和你注意到的bsf。作为比较点,我也为您的 while 循环生成了程序集。正如您在 +6 指令和几次跳转中所说的那样,它用纯 C 语言完成了任务。就我而言,我将利用内置的,但对于更便携的解决方案,while 循环也很有效。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-15
  • 2018-06-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
  • 1970-01-01
  • 2020-01-09
相关资源
最近更新 更多