虽然所有 POSIX 编程接口都按原样使用设备号(dev_t 类型),但 FUZxxl 在对此答案的评论中指出,常见的UStar 文件格式——最常见的 tar 归档格式——确实会拆分设备号分为主要和次要。 (它们通常每个编码为七个八进制数字,因此出于兼容性原因,应该限制为 21 位无符号主要和 21 位无符号次要。这也意味着将设备号映射到仅主要或仅次要不是可靠的方法。)
以下内容包括在Jonathon Reinhart's answer 上扩展的文件,在网上挖掘各种系统手册页和文档(makedev()、major() 和minor())后,加上这个问题的 cmets。
#if defined(custom_makedev) && defined(custom_major) && defined(custom_minor)
/* Already defined */
#else
#undef custom_makedev
#undef custom_major
#undef custom_minor
#if defined(__linux__) || defined(__GLIBC__)
/* Linux, Android, and other systems using GNU C library */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(_WIN32)
/* 32- and 64-bit Windows. VERIFY: These are just a guess! */
#define custom_makedev(dmajor, dminor) ((((unsigned int)dmajor << 8) & 0xFF00U) | ((unsigned int)dminor & 0xFFFF00FFU))
#define custom_major(devnum) (((unsigned int)devnum & 0xFF00U) >> 8)
#define custom_minor(devnum) ((unsigned int)devnum & 0xFFFF00FFU)
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
/* FreeBSD, OpenBSD, NetBSD, and DragonFlyBSD */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(__APPLE__) && defined(__MACH__)
/* Mac OS X */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(_AIX) || defined (__osf__)
/* AIX, OSF/1, Tru64 Unix */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(hpux)
/* HP-UX */
#include <sys/sysmacros.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(sun)
/* Solaris */
#include <sys/types.h>
#include <sys/mkdev.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#else
/* Unknown OS. Try a the BSD approach. */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#if defined(makedev) && defined(major) && defined(minor)
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#endif
#endif
#if !defined(custom_makedev) || !defined(custom_major) || !defined(custom_minor)
#error Unknown OS: please add definitions for custom_makedev(), custom_major(), and custom_minor(), for device number major/minor handling.
#endif
#endif
可以从现有的支持 UStar 格式的存档器中收集其他定义。在我看来,与每个操作系统/架构上的现有实现兼容是最重要的。
以上内容应涵盖所有使用 GNU C 库、Linux(包括 Android)、FreeBSD、OpenBSD、NetBSD、DragonFlyBSD、Mac OS X、AIX、Tru64、HP-UX 和 Solaris 的系统,以及任何定义宏的系统<sys/types.h> 包括在内。 Windows 部分,我不确定。
据我了解,Windows 对所有普通文件使用设备 0,对设备使用 HANDLE(空指针类型)。我完全不确定上述逻辑在 Windows 上是否合理,但许多旧系统将设备编号的 8 个最低有效位放入次要位,将接下来的 8 位放入主要位,约定似乎是任何剩余位也将被放入(不转移)小调。检查现有的 UStar 格式的 tar 档案并参考设备会很有用,但我个人根本不使用 Windows。
如果未检测到系统,并且系统未使用 BSD 样式的包含来定义宏,则上述将错误停止编译。 (我会亲自添加编译时机制,以帮助找到正确的标头定义,例如使用 find、xargs 和 grep,以防发生这种情况,并建议将添加内容也发送到上游。@ 987654335@ 应该显示所有预定义的宏,以帮助识别操作系统和/或 C 库。)
最初,POSIX 声明 dev_t 必须是算术类型(因此,理论上,在某些系统上它可能是 float 或 double 的某种变体),但 IEEE Std 1003.1, 2013 Edition 说它必须是整数类型。我敢打赌,这意味着没有已知的 POSIX-y 系统曾经使用过浮点 dev_t 类型。看起来 Windows 使用 void 指针或HANDLE 类型,但 Windows 无论如何都不符合 POSIX。