linux内核函数 ffs,linux内核中的宏ffs(x)【转】

linux内核中ffs(x)宏是平台相关的宏,在arm平台,该宏定义在

arch/arm/include/asm/bitops.h

#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })

fcecaa27ea5212ceb9bf034c36bfbf34.gif

static inline int fls(int x)

{

int ret;

if (__builtin_constant_p(x))

return constant_fls(x);

asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");

ret = 32 - ret;

return ret;

}

fcecaa27ea5212ceb9bf034c36bfbf34.gif

__t & -__t   等于找到__t 第一个为1的位(从低位开始),并把该位保留为1其余位清0.

例如 一32位整形数 6,用二进制表示它的低8位:00000110,  都知道负数为最高为1其余位取反加1.-6即 11111010

相与得 00000010,即6&-6. 把该值传递给函数fls().

再看fls函数.

if (__builtin_constant_p(x))

return constant_fls(x);

__builtin_constant_p 是Gcc的内建函数 ,用于判断一个值是否为编译时常数,如果参数的值是常数,函数返回 1,否则返回 0。

如果是常数就用下面函数计算00000010中1的位置

fcecaa27ea5212ceb9bf034c36bfbf34.gif

static inline int constant_fls(int x)

{

int r = 32;

if (!x)

return 0;

if (!(x & 0xffff0000u)) {

x <<= 16;

r -= 16;

}

if (!(x & 0xff000000u)) {

x <<= 8;

r -= 8;

}

if (!(x & 0xf0000000u)) {

x <<= 4;

r -= 4;

}

if (!(x & 0xc0000000u)) {

x <<= 2;

r -= 2;

}

if (!(x & 0x80000000u)) {

x <<= 1;

r -= 1;

}

return r;

}

fcecaa27ea5212ceb9bf034c36bfbf34.gif

算法就是折半法,这个函数计算的是从高位起第一个1位的位置.00000010, r=2.  由于__t&-__t只有一个1,所以就是找到该1的位置.

如果输入参数是00001010 那么 r=4.

如果参数是变量,直接使用arm指令运算.

执行   asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");

ret = 32 - ret;

CLZ(Count Leading Zeros)指令对Rm中值的高位(leading zeros)个数进行计数,结果放到Rd中。若源寄存器全为0,则结果为32。若[31]为1,则结果为0。

clz指令计算高位0的个数, 然后拿32-ret 算出1的位置.

所以,ffs(x)这个宏的值就是x的第一个1的位置(从低位开始,数值从1开始,0代表x全0).

另外,该文件中还有很多linux关于位操作的函数,可以作为自己写应用程序时的有用参考.

原文:https://www.cnblogs.com/sky-heaven/p/12206882.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值