用stat()比较st_dev是最直接的方法:Linux/macOS通过st_dev判断是否同文件系统实例,Windows需用GetVolumePathName()归一化卷根后字符串比较,二者语义不等价,不可统一抽象。

用 stat() 比较 st_dev 是最直接的方法
Linux/macOS 下,两个路径是否在同一个物理设备(比如同一块 SSD 或同一分区),本质是看它们的文件系统设备号是否一致。这个信息就藏在 struct stat 的 st_dev 字段里——不是 st_rdev,后者是设备文件本身的主/次设备号,容易混淆。
实操要点:
-
stat()必须作用于**实际存在的路径**,对不存在的路径会失败,返回 -1 并设置errno - 如果路径是符号链接,
stat()返回的是目标文件的st_dev;若要获取链接文件自身(即链接所在位置)的信息,得用lstat() - 注意跨挂载点行为:即使两路径看起来都在
/mnt下,只要挂载了不同设备(如 NFS、tmpfs、bind mount),st_dev就不同
示例判断逻辑:
#include <sys/stat.h>
bool on_same_device(const char* p1, const char* p2) {
struct stat s1, s2;
if (stat(p1, &s1) != 0 || stat(p2, &s2) != 0) return false;
return s1.st_dev == s2.st_dev;
}
Windows 上没有 st_dev,得用 GetVolumePathName() + GetDiskFreeSpaceEx()
Windows 不暴露统一的设备 ID,st_dev 在 MinGW/MSVC 中只是模拟值(通常按驱动器盘符生成),不可靠。真实等价做法是提取路径所属卷的根路径,再比对是否相同。
立即学习“C++免费学习笔记(深入)”;
关键步骤:
- 先调用
GetVolumePathNameA()(或宽字符版)把任意路径(如C:\foo\bar.txt)转成卷根(C:\) - 对两个路径分别做这一步,然后字符串比较结果是否相等
- 注意:
\servershare这类网络路径会映射到某个驱动器(如Z:),也能被正确归一化;但纯 UNC 路径(未映射)需额外处理,GetVolumePathName()对其可能失败
简写示意(错误检查略):
char vol1[MAX_PATH], vol2[MAX_PATH]; GetVolumePathNameA(path1, vol1, sizeof(vol1)); GetVolumePathNameA(path2, vol2, sizeof(vol2)); return strcmp(vol1, vol2) == 0;
跨平台封装时,别硬套 POSIX 语义
有人试图用 std::filesystem::canonical() 后比较路径字符串,这是错的——canonical() 只解决符号链接和 ..,不反映设备归属;两个不同设备上的 /home/a 和 /mnt/backup/a 可能 canonical 后路径不同,但更糟的是,同一设备上两个挂载点(如 / 和 /home)canonical 后路径也不同,却仍属同一设备。
真正跨平台的底线做法:
- Linux/macOS:坚持用
stat()+st_dev - Windows:坚持用
GetVolumePathName()归一化卷根 - 不要尝试“统一抽象”出一个叫
device_id的跨平台类型——它在 Windows 上本就不存在语义等价物 - 若项目已用
std::filesystem,注意std::filesystem::status()不提供设备信息,C++20 的std::filesystem::space()也只返回空闲/总空间,不暴露设备标识
容易被忽略的挂载边界:bind mount、overlayfs、/proc/sys/fs
Linux 下看似同根的路径,可能因特殊挂载而分属不同设备。比如:
-
/proc、/sys、/dev是虚拟文件系统,st_dev各自独立,且与磁盘设备无关 - 用
mount --bind把/mnt/data绑到/home/user/data,两者st_dev相同(因为是同一设备上的同一文件系统) - 但用
overlayfs或chroot配合 pivot_root 后,st_dev可能被内核重映射,此时仅靠用户态stat()不足以判定底层物理设备一致性 - 容器场景下(如 Docker),
/proc/1/root下的路径和宿主机路径可能有相同st_dev,但物理存储未必共用——这时需要结合 cgroup device 白名单或/sys/block设备拓扑分析,已超出单纯路径比较范畴
也就是说,st_dev 相等只保证“同文件系统实例”,不绝对等于“同物理磁盘”。真要追到底层磁盘,得查 /sys/dev/block/*/device 或 lsblk 输出,那已经是运维级诊断了。



















