用stat()比较st_dev是最可靠方式:linux/macos下通过stat()获取两路径的st_dev字段并比对是否相等,可准确判断是否位于同一文件系统实例;windows需用getvolumepathname()结合getvolumeinformation()获取卷序列号判断。

用 stat() 比较 st_dev 是最可靠方式
Linux/macOS 下,两个路径是否在同一个物理磁盘分区,本质是看它们的文件系统设备号是否一致。这不能靠字符串比较路径、也不能看挂载点,必须查内核返回的底层设备标识。stat() 系统调用返回的 st_dev 字段就是这个设备号——同一块物理分区(或同一逻辑卷)上的所有文件,st_dev 值完全相同。
注意:st_dev 不是磁盘序号(如 /dev/sda1),而是内核为已挂载文件系统分配的唯一主/次设备号组合;不同挂载点即使映射到同一块磁盘(比如 /mnt/a 和 /mnt/b 都挂载自 /dev/nvme0n1p2),只要挂载的是同一个文件系统实例,st_dev 就一样。
- 必须对两个路径都调用
stat()(不是lstat()),否则符号链接会跳转失败 - 路径需存在且可访问,否则
stat()返回 -1,要检查errno - Windows 不支持
st_dev语义,该方案仅适用于 POSIX 系统
#include <sys>
#include <unistd.h><p>bool on_same_device(const char<em> p1, const char</em> p2) {
struct stat s1, s2;
if (stat(p1, &s1) != 0 || stat(p2, &s2) != 0) return false;
return s1.st_dev == s2.st_dev;
}</p></unistd.h></sys>
Windows 上得用 GetVolumePathName() + GetDiskFreeSpaceEx()
Windows 没有等价于 st_dev 的跨驱动器抽象,但可以通过路径归一化到卷根,再比对卷标识符。核心是先用 GetVolumePathName() 把任意路径转成对应卷的根路径(如 C:\foo\bar → C:\),然后对两个根路径分别调用 GetDiskFreeSpaceEx(),检查返回的 *lpFreeBytesAvailable 等字段是否指向同一存储后端——但这不保险;更稳的方式是用 GetVolumeInformation() 取 lpVolumeSerialNumber,它在同一卷上恒定不变。
-
GetVolumePathName()必须传入完整路径,相对路径可能失败 - 注意宽字符:Windows API 默认用
wchar_t*,C++ 中需用std::wstring或L"..." -
lpVolumeSerialNumber是卷级序列号,不是磁盘物理序列号,重格式化后会变
别用 realpath() 或路径字符串匹配来判断
有人试图用 realpath() 展开路径再比前缀,这是错的。比如 /home 和 / 可能分属不同分区(/home 单独挂载),但 /home/user 的 realpath 仍是 /home/user,和 / 字符串毫无关系;反过来,/mnt/data 和 /data 路径无关,却可能映射到同一块 NVMe 分区。
-
realpath()解决的是符号链接和..归一化,和底层存储无关 - 硬链接也无法跨分区创建,所以“能否创建硬链接”可作为间接验证手段,但不能替代
stat() - 容器或 bind mount 场景下,
st_dev仍有效,因为内核视角里仍是同一挂载实例
跨平台封装要注意 st_dev 和 dwVolumeSerialNumber 的语义差异
写跨平台工具时,别强行统一接口返回“设备 ID”。POSIX 的 st_dev 是数值型、可直接比较相等;Windows 的卷序列号是 32 位整数,但含义不同——它不保证全局唯一(尤其 FAT32),且不反映物理磁盘拓扑。如果业务真依赖物理磁盘一致性(比如想避开同一 SSD 的多分区做冗余写入),Windows 侧必须进一步调用 IOCTL_STORAGE_QUERY_PROPERTY 查 StorageAdapterProperty,成本高、需管理员权限。
- 普通应用只需“是否同文件系统”,用各自原生 API 即可
- 不要把
st_dev直接 cast 成 Windows 卷序列号去比较 - CI/CD 或 Docker 环境中,
/proc/mounts可辅助验证,但运行时不可依赖
真正难的不是调哪个函数,而是意识到“同一分区”在不同系统里根本不是一个定义——Linux 看挂载实例,Windows 看卷,而裸金属、LVM、ZFS、btrfs 还各有解释。没银弹,得按目标环境选最贴近的指标。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











