如何有效地将位位置提取为C中的值
How to efficiently extract the bit position as a value in C
我正在寻找一种有效的(最好是宏)方法来提取位的位置并将其保存为 C 中的值。
data = 0x4000
会产生:
pos = 14
我正在读取的 16 位寄存器中只会设置一位。目前,我只是将数据与移位值进行比较以提取位置,但肯定有更好的方法我不知道。
我花了一些时间在这里搜索类似的问题,但找不到。
现代处理器只有一条指令来执行此操作(计算尾随零、查找第一组、计算前导零并查找最后一组)。在 gcc 和 clang 中,__builtin_ctz(n)
将 return 数字中尾随零的数量。在支持单指令 ctz 的处理器上,它编译为一条指令。确保使用足够宽的函数(即 __builtin_ctz
代表 int
或更窄,__builtin_ctzl
代表 long int
或更窄,或者 __builtin_ctzll
代表 long long int
或更窄。对于 16 位寄存器,__builtin_ctz
应该足够了。
有关详细信息,请参阅 gcc documentation and wikipedia。
与平台无关的解决方案是最可移植和最有效的解决方案,但它也是悲观的;许多现代处理器都有像这样的位操作的指令和内在函数。
例如,x86-64 有 bsf
指令,该指令将使用另一个操作数中最高有效设置位的位置填充一个操作数:
bsf eax, 0x00004000
; eax now holds the value '14'
但是,'pure' C 解决方案看起来像:
int MSBPos = 0;
while(data && !(data & 1)) // 'data' check avoids infinite loop if data is 0
{
MSBPos++;
data >>= 1;
}
注意,这仅适用于 OP 保证整个值中有一个设置位且所有其他位均为 0 的情况。
不过我不担心它是线性算法;位操作非常快。
我正在寻找一种有效的(最好是宏)方法来提取位的位置并将其保存为 C 中的值。
data = 0x4000
会产生:
pos = 14
我正在读取的 16 位寄存器中只会设置一位。目前,我只是将数据与移位值进行比较以提取位置,但肯定有更好的方法我不知道。
我花了一些时间在这里搜索类似的问题,但找不到。
现代处理器只有一条指令来执行此操作(计算尾随零、查找第一组、计算前导零并查找最后一组)。在 gcc 和 clang 中,__builtin_ctz(n)
将 return 数字中尾随零的数量。在支持单指令 ctz 的处理器上,它编译为一条指令。确保使用足够宽的函数(即 __builtin_ctz
代表 int
或更窄,__builtin_ctzl
代表 long int
或更窄,或者 __builtin_ctzll
代表 long long int
或更窄。对于 16 位寄存器,__builtin_ctz
应该足够了。
有关详细信息,请参阅 gcc documentation and wikipedia。
与平台无关的解决方案是最可移植和最有效的解决方案,但它也是悲观的;许多现代处理器都有像这样的位操作的指令和内在函数。
例如,x86-64 有 bsf
指令,该指令将使用另一个操作数中最高有效设置位的位置填充一个操作数:
bsf eax, 0x00004000
; eax now holds the value '14'
但是,'pure' C 解决方案看起来像:
int MSBPos = 0;
while(data && !(data & 1)) // 'data' check avoids infinite loop if data is 0
{
MSBPos++;
data >>= 1;
}
注意,这仅适用于 OP 保证整个值中有一个设置位且所有其他位均为 0 的情况。
不过我不担心它是线性算法;位操作非常快。