0
点赞
收藏
分享

微信扫一扫

__builtin_ffs 的使用方法


前言

  • __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_test2

0, 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

__builtin_ffs 的使用方法_最小值

应用方法

  • 获取最高优先级的方法,位示图法
  • 每个优先级,从低到高,占一个位
  • 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

__builtin_ffs 的使用方法_i++_02

小结

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


举报

相关推荐

0 条评论