前言

  • __builtin_ffs 在Linux 系统上比较的常见,有一些其他的操作系统,也会看到 __builtin_ffs的使用,作用到底是什么?
  • 如何正确的使用 __builtin_ffs?

作用

  • __builtin_ffs 是 gcc 内置的函数,获取一个数值:从低位起,第一个1 出现的位置,如0x11,返回的是1,0x00返回的是0,0x02,返回的是2
  • 在Keil MDK armcc的编译环境下,需要使用 --gnu的编译选项,armclang 默认支持 gnu选项,所以不需要手动设置

测试环境

  • Keil MDK5,这里查看 __builtin_ffs 的返回值,什么场景下需要计算第一个1的返回位置呢?如操作系统的优先级算法中,低位代表高优先级,第一个出现1的位,代表最高的优先级
  • uCOS-II 的优先级判定表格,其实就是 __builtin_ffs 计算出来的值

测试代码

  • 这里使用RT-Thread Keil MDK5 环境, shell命令验证
struct _ffs
{const char *name;rt_uint32_t value;
};
typedef struct _ffs ffs_t;#define FFS_ITEM(a)     { #a, a }static ffs_t ffs_tbl[] =
{FFS_ITEM(0x00),FFS_ITEM(0x01),FFS_ITEM(0x02),FFS_ITEM(0x04),FFS_ITEM(0x08),FFS_ITEM(0x10),FFS_ITEM(0x11),FFS_ITEM(0x12),FFS_ITEM(0x14),FFS_ITEM(0x18),FFS_ITEM(0x20)
};void builtin_ffs_test(void)
{rt_uint32_t tbl_size = sizeof(ffs_tbl) / sizeof(ffs_tbl[0]);for (rt_uint32_t i = 0; i < tbl_size; i++){rt_kprintf("%s -> %d\r\n", ffs_tbl[i].name, __builtin_ffs(ffs_tbl[i].value));}
}MSH_CMD_EXPORT(builtin_ffs_test, builtin_ffs_test);void builtin_ffs_test2(void)
{for (rt_uint32_t i = 0; i < 256; i++){if ((i % 16) == 0x00)rt_kprintf("\r\n");rt_kprintf("%d, ", __builtin_ffs(i));}rt_kprintf("\r\n");
}
MSH_CMD_EXPORT(builtin_ffs_test2, builtin_ffs_test2);

测试结果

msh >builtin_ffs_test
0x00 -> 0
0x01 -> 1
0x02 -> 2
0x04 -> 3
0x08 -> 4
0x10 -> 5
0x11 -> 1
0x12 -> 2
0x14 -> 3
0x18 -> 4
0x20 -> 6
  • 这里需要注意:如果第一位为1,就返回的是1,而不是0(C语言一般以0 作为起始)
msh >builtin_ffs_test20, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
6, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
7, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
6, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
8, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
6, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
7, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
6, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1,
  • 注意:这个跟uCOS-II 的优先级列表对比,发现除了 第一个0之外,都多了一个1,这是因为 uCOS-II 的优先级判断表,0x01 的1 为BIT0 位置,所以需要: __builtin_ffs(value) - 1

应用方法

  • 获取最高优先级的方法,位示图法
  • 每个优先级,从低到高,占一个位
  • 1024 个优先级
  • 1024 / 32 = 32 (32个组),每组 32个优先级(每位代表一个优先级)
  • uint32_t prio_group
  • uint32_t prio_table[32]
  • 优先级设置时,由两部分组成:纵坐标 Y, 横坐标X ,优先级 = Y * 32 + X
  • 优先级存在,相应的组 prio_group 置位, prio << 5 响应的 prio_table 置位 prio_table[prio << 5] |= 1 << prio % 32
  • 最高优先级:最低位为最高优先级
  • 在优先级组 prio_group 中从低位开始,找到第一个1的位置,也就是最高优先级的组,如prioBitY
  • 在 prio_table[prioBitY]中,从低位开始,找到第一个1的位置,如prioBitX
  • 获取的最高优先级(数值最小的)为: prioBitY << 5 + prioBitX

小结

  • 这部分的计算很巧妙,可以快速的获取一个数值,如32位数值,从低位开始,第一个1出现的位置
  • 通过分组,可以很快的查找【位图】中最小的数值

__builtin_ffs 的使用方法相关推荐

  1. 在 Oracle Enterprise Linux 和 iSCSI 上构建您自己的 Oracle RAC 11g 集群

    作者:Jeffrey Hunter 了解如何以低于 2,700 美元的费用在 Oracle Enterprise Linux 上安装并配置 Oracle RAC 11g 第 2 版开发集群. 本指南中 ...

  2. Java面试题大全2021版

    一.Java 基础 JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Run ...

  3. Keil MDK5 编译报Undefined symbol __builtin_ffs 的错误的解决方法

    问题描述 __builtin_ffs 的作用,就是求一个32位数值中,从低位开始的1出现的位置,这算是一个内置的函数,所以直接使用,计算会比较的快. RT-Thread 内核代码中,使用这个 函数,作 ...

  4. Kotlin协程使用,协程使用注意事项,协程中的await方法使用|不使用suspend使用协程

    参见 码云 协程使用方法一 (Dispatchers调度器模式) 指定不同线程.同线程会挂起并阻塞(挂起是不影响主线程执行,阻塞是同样的IO线程会阻塞) withContext(Dispatchers ...

  5. IDEA中将代码块封装为方法,IDEA代码重构快捷键

    IDEA中将代码块封装为方法 选中要转换的代码块,快捷键: Windows快捷键:Alt + Shift + M Mac快捷键:Alt + Command + M 如图:

  6. IDEA自动生成对象所有set方法

    idea中有一款插件能够生成对象所有的set方法,GenerateAllSetter :下载地址 步骤1:将下载好的压缩包放在自己记得的文件夹中,在idea中进行导入 步骤2:在本地选中刚才的压缩包, ...

  7. List元素互换,List元素转换下标,Java Collections.swap()方法实例解析

    Java Collections.swap()方法解析 jdk源码: public static void swap(List<?> list, int i, int j) {// ins ...

  8. java1.8新增超实用Map方法——Map.getOrDefault()和Map.value()方法详解

    1. Map.getOrDefault() 翻译一下官方解释: java.util.Map<K, V> V getOrDefault(Object key, V defaultValue) ...

  9. spring boot项目 中止运行 最常用的几种方法

    spring boot项目 中止运行 最常用的几种方法: 1. 调用接口,停止应用上下文 @RestController public class ShutdownController impleme ...

最新文章

  1. ssm开发框架原理_SSM 单体框架 - 前端开发:视频讲解
  2. Context-----Activity,Application之间的交流使者
  3. js中Window跟window的区别
  4. Linux下静态库的创立与使用
  5. 在 Excel 中如何使用宏示例删除列表中的重复项
  6. flutte的第一个hello world程序
  7. Lyft Level 5 Challenge 2018 - Elimination Round翻车记
  8. 关于#include头文件问题
  9. 服务器503能自动恢复吗,服务器出现503错误的原因与解决方法
  10. 问题六十九:阴影(Shadow)——原理和C++实现
  11. Mysql 主从复制简易操作指南
  12. winpcap java封装_利 用jnetpcap 封装libpcap
  13. Python可视化--常用颜色
  14. MFC中窗口类、句柄的获取
  15. 南京大学2021计算机考研复试线是多少,快讯!南京大学2021年考研复试线公布,金融专硕425分!...
  16. 国内6大网络信息采集和页面数据抓取工具
  17. Tungsten Fabric解决方案指南-Gateway MX
  18. python是什么和c++是什么区别_编程c++和python的区别
  19. 【图形学】布林冯BlinnPhong
  20. mysql变量环境配置文件_Day44 Mysql环境变量、配置文件(2)

热门文章

  1. XBOX登录白屏,微软商店无法连接网络
  2. 文件路径名太长导致IAR编译报错:Fatal Error[Pe1696]: cannot open source file
  3. 最好的跑步耳机推荐、盘点五款公认最好的跑步耳机
  4. Blender雕刻模块:2.81新功能遮罩提取(Mask Extract)
  5. mysql建表是要注意什么问题_MySQL建表注意事项
  6. HTML5期末大作业:动漫人物介绍网站设计——柯南(5页) 含报告 HTML+CSS+JavaScript dw网页设计 web网页设计与开发
  7. 前端绘制小猪佩奇(CSS)
  8. 欧几里德算法、拓展欧几里德、中国剩余定理
  9. 远程办公:通过cpolar内网穿透,远程桌面控制家里公司内网电脑
  10. 物联网场景下,基于无线宽带的空中组网研究