ffs和 ffsll是 POSIX的基础部分吗,还是X/Open系统接口的一部分?

编程语言 2026-07-09

我开发了一个应用,需要在一个相当稀疏的位集合中快速定位位。理想情况下我会使用__builtin_ffsll()ffsll(),但ffs()也能凑合,我只是需要在每个uint64_t上不必要地调用它两次。我希望我的程序能够在任何POSIX环境下编译通过,即使C 编译器缺少__builtin_ffsll()。我可以通过对GCC的存在性和版本进行检查来检测其存在,并对较新版本的GCC与并非太新的clang版本使用__has_builtin

GNU/Linux的手册页指出,ffs() 至少在与_XOPEN_SOURCE配合时可用,并且在700及以上的版本中也可用;在200809L之前的版本中也能与_POSIX_C_SOURCE一起使用。因此据glibc团队所述,它曾是基础POSIX的一部分,但出于某种原因在POSIX 2008中移到了X/Open系统接口。

根据 Open Group,它在Issue 5中从X/Open系统接口移到了基础POSIX。据我理解,这其实是一个非常早的POSIX版本。我找到了一个关于系统接口和头文件的PDF,它是Issue 5,提及POSIX 1996,因此看起来POSIX Issue 5就是POSIX 1996。

不过,同一Open Group关于ffs的页面上,包含文件strings.h以及三个函数ffsffslffsll都位于一个提及XSI或 X/Open系统接口的注释中。因此POSIX的信息似乎存在矛盾。

此外,遗憾的是,即便Ubuntu 26.04看起来把_POSIX_VERSION设为202405L,如果我定义_POSIX_C_SOURCE=202405L_XOPEN_SOURCE=800,似乎也不能使用ffsll,而据 Stack Overflow的回答 应该会从POSIX 2024导入XSI的内容。

那么,POSIX中ffsffsll的历史究竟是怎样的?它们最初是基础POSIX的一部分然后移到XSI(因此关于Issue 5的结尾注记可能被错误颠倒),还是最初属于XSI,随后移到了基础POSIX,而POSIX标准化人员忘记从定义中移除XSI的注记?如果Ubuntu 26.04 LTS有_POSIX_VERSION=202405L,却没有_POSIX_C_SOURCE=202405L_XOPEN_SOURCE=800,导致ffsll不可见,这显然是glibc的一个bug。

解决方案

概要部分 你可以看到 ffsffsl、和 ffsll 被阴影标示,并且位于标记为XSI的选项标记之间(带有内部的X 的箭头),这意味着这些函数属于X/Open系统接口(XSI)选项的一部分。也就是说,这些函数并非“基础” POSIX,你必须定义 _XOPEN_SOURCE 而不是 _POSIX_C_SOURCE。你说得对,对于 ffslffsll 应该设为800,因为它们是在Issue 8(2024)中新加入的,而glibc也许尚未对这点进行更新;目前你仍然需要为它们定义 _DEFAULT_SOURCE(或 _GNU_SOURCE)。

至于 ffs 的历史,它最初在X/Open Portability Guide (XPG) 的System Interfaces and Headers第 4版、第2 次发行中新增,后来成为单UNIX规范(SUSv1)的一部分。然而,在该文档中它并非基础接口;它属于X/Open UNIX扩展,因此被标记为 UX。Issue 5(属于SUSv2)将整个扩展移动到了基础的X/Open接口,因此这段文字被添加到了所有原有 UX 接口的变更历史部分:

从X/OPEN UNIX扩展移动到BASE。

在Issue 5内,ffs 被标记为 EX,因为它并非POSIX的一部分。SUS在 2001年之前是POSIX的超集,随后合并为POSIX.1-2001/SUSv3(Issue 6)。SUS的额外内容(如 ffs)成为了你今天所看到的XSI选项。因此,ffs 既不是也从来不是base POSIX的部分。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章