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

arch/arm/include/asm/bitops.h

#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
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 = - ret;
return ret;
}

__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的位置

static inline int constant_fls(int x)
{
int r = ; if (!x)
return ;
if (!(x & 0xffff0000u)) {
x <<= ;
r -= ;
}
if (!(x & 0xff000000u)) {
x <<= ;
r -= ;
}
if (!(x & 0xf0000000u)) {
x <<= ;
r -= ;
}
if (!(x & 0xc0000000u)) {
x <<= ;
r -= ;
}
if (!(x & 0x80000000u)) {
x <<= ;
r -= ;
}
return r;
}

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

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

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

执行   asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
           ret = - 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关于位操作的函数,可以作为自己写应用程序时的有用参考.

linux内核中的宏ffs(x)的更多相关文章

  1. 剖析linux内核中的宏---------container_of

    #define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); ...

  2. Linux内核中container_of宏的详细解释

    上一节拒绝造轮子!如何移植并使用Linux内核的通用链表(附完整代码实现)我们在分析Linux内核链表的时候注意到内核在求解结构体偏移的时候巧妙的使用了container_of宏定义,今天我们来详细剖 ...

  3. Linux内核中的宏:__init and __exit

    ZZ FROM: http://blog.csdn.net/musein/article/details/742609 ======================================== ...

  4. 剖析linux内核中的宏-----------offsetof

    offsetof用于计算TYPE结构体中MEMBER成员的偏移位置. #ifndef offsetof#define offsetof(TYPE, MEMBER) ((size_t) &((T ...

  5. Linux内核中的fastcall和asmlinkage宏

    代码中看见:#define _fastcall 所以了解下fastcall -------------------------------------------------------------- ...

  6. (十)Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  7. Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  8. Linux内核中的常用宏container_of其实很简单【转】

    转自:http://blog.csdn.net/npy_lp/article/details/7010752 开发平台:Ubuntu11.04 编 译器:gcc version 4.5.2 (Ubun ...

  9. 向linux内核中添加外部中断驱动模块

    本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...

随机推荐

  1. 并发和多线程(六)--ThreadLocal

    ThreadLocal是什么? 当使用ThreadLocal修饰变量的时候,ThreadLocal会为每个使用该变量的线程提供独立的变量副本,每个线程可以独立改变自己的副本,而不 影响其他线程的变量副 ...

  2. 05网页<div></div>块内容

    网页<div></div>块内容 <header>此处为新 header 标签的内容</header> <navigation>此处为新 n ...

  3. Java真实笔试题一

    PS:昨天去笔试后,发现自己对于JavaSE的基础部分还是有些薄弱的地方,特将昨天自己不是太清楚的地方记录下来,巩固基础. 子类继承父类静态方法的问题 public class Study { pub ...

  4. buf.writeDoubleBE()函数详解

    buf.writeDoubleBE(value, offset[, noAssert]) buf.writeDoubleLE(value, offset[, noAssert]) value {Num ...

  5. Java Arrays.sort相关用法与重载

    Java Arrays.sort() Java中的数组排序函数, 头文件 import java.util.Arrays; 相关API Arrays.sort(arys[]) Arrays.sort( ...

  6. 清空所有Session

    //清空所有Session request.getSession().invalidate();

  7. HDU 1573 解同余模线性方程组

    题目意思很直接就是一道裸的解线性同余模方程组的题目 #include <cstdio> #include <cstring> using namespace std; #def ...

  8. MTK平台系统稳定性分析

    目录 1:简介 2:怎么抓取和分析log 3:怎么确定问题点 简介 系统稳定性目前主要是解决系统死机重启. 分为两部分:Android /kernel Kernel 分析需要的文件和工具: Mtklo ...

  9. vue.js编程式路由导航 --- 由浅入深

    编程式路由导航 实例中定义一个方法,这个方法绑定在标签上 然后就设置路由跳转 语法 this.$router.history.push('要跳转路由的地址') <!DOCTYPE html> ...

  10. 【BZOJ3790】神奇项链(manacher,树状数组)

    题意: 思路:生成一些回文拼起来使生成的段数最小 显然存在一种最优的方案,使生成的那些回文是目标串的极长回文子串 求出对于每个位置的最长回文子串,问题就转化成了: 给定一些已知起始和终止位置的线段,求 ...