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. Objective-C中copy 、retain以及ARC中新加入的strong、weak关键字的含义

    copy: 创建一个引用计数为1的对象,然后释放旧的对象 retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的引用计数为 1 Copy其实是建立了一个相同的对象,而retain不是: ...

  2. Jenkins系列之Jenkins的安装(一)

    自动化测试的时候通常我们都会进行持续集成,下面是持续集成工具Jenkins的安装 Jenkins优点: 开源免费 跨平台,支持所有的平台 web形式的可视化的管理页面 安装配置超级简单 tips及时快 ...

  3. R函数详解

    字符串连接函数paste 1.字符串连接:paste(..., sep = " ", collapse = NULL)sep表示分隔符,默认为空格.collapse表示如果不指定值 ...

  4. CodeFrist基础_迁移更新数据

    一丶自动迁移 第一次启用迁移:NeGet-->Enable-Migrations public DemoDbContext() : base("name=ConncodeFirst&q ...

  5. Linux学习笔记记录(三)

    压缩: 例如将/etc 目录压缩为压缩包tar -cjvf  /aaa.tar.bz2  /etc           tar -czvf /aaa.tar.gz  /etc 解压: tar -xjv ...

  6. Linux mpstat-显示各个可用CPU的状态

    更多linux 性能监测与优化 关注:linux命令大全 mpstat命令指令主要用于多CPU环境下,它显示各个可用CPU的状态系你想.这些信息存放在/proc/stat文件中.在多CPUs系统里,其 ...

  7. Servlet监听器的使用

    Servlet监听器的使用 制作人:全心全意 在Servlet技术中已经定义了一些事件,并且可以针对这些事件来编写相关的事件监听器,从而对事件做出相应的处理.例如,想要在Web应用程序启动和关闭时来执 ...

  8. 51nod 1285 山峰和分段

    [题解] 枚举n的各个因数作为段长,O(n)判断每一段内是否有山峰即可. #include<cstdio> #include<cstring> #include<algo ...

  9. Windows Server 2008R2服务器IIS安装步骤

    注意点: 添加ASP.NET ..NET 扩展性.CGI.ISAPI 扩展.ISAPI 筛选器,去掉 目录浏览(因为大多数网站用不到.) 如果需要用到asp则勾选asp,如果需要用shtm需要开启在服 ...

  10. Ural 1091 Tmutarakan Exams

    Tmutarakan Exams Time Limit: 1000ms Memory Limit: 16384KB This problem will be judged on Ural. Origi ...