std::filesystem::path 的奇怪运算符/

Posted

技术标签:

【中文标题】std::filesystem::path 的奇怪运算符/【英文标题】:Strange operator/ of std::filesystem::path 【发布时间】:2020-08-19 11:34:37 【问题描述】:
auto path = std::filesystem::path("c:") / "PosteClient.log";

导致 c:PosteClient.log 而不是 c:\PosteClient.log

这对我来说是一种奇怪的行为,因为无法使用 windows 上的结果,例如

CreateFile("c:PosteClient.log")

以 ERROR_FILE_NOT_FOUND 失败。

我在文档中找不到这种行为的原因,但从示例中看起来这是预期的行为。 https://en.cppreference.com/w/cpp/filesystem/path/append

我想了解为什么会出现这样的行为,以便为我的代码找到适合使用此运算符的所有场景的合适解决方案

好吧,让我们更准确地说,假设我有以下代码:

HANDLE CreateHandleFromPath(const std::filesystem::path& path, const std::string& fileName)

    auto pathComplete = path / fileName;

    auto* hFile = CreateFileW(
        pathComplete.wstring().c_str(),
        GENERIC_READ,
        FILE_SHARE_READ, nullptr, OPEN_EXISTING,
        0,
        nullptr);

    if (hFile == INVALID_HANDLE_VALUE || hFile == nullptr)
    
        throw std::filesystem::filesystem_error(
            "Can't get handle",
            std::error_code(::GetLastError(), std::system_category()));
    

    return hFile;

工作目录是

C:\SRC\ConsoleApplication3\

当我现在调用这段代码时

CreateHandleFromPath(std::filesystem::path("c:\\"), "test.log")

函数成功,因为结果路径是“c:\test.log”

CreateHandleFromPath(std::filesystem::path("c:"), "test.log")

函数失败,因为结果路径是“c:test.log”

我无法控制调用者。 当然,在这里进行检查并手动添加分隔符很容易,但这意味着我可以一直自己做,不需要操作员,或者更准确地说,我自己添加更安全,因为这将适用于所有情况,操作员/适用于所有人,除非有人使用没有反斜杠的驱动器号调用。我只想了解为什么该功能会这样工作,因为我认为有一个我目前看不到的原因

【问题讨论】:

我认为这种行为仅限于 Windows 上的驱动器号。但是你知道它存在,你可以手动添加文件分隔符:std::filesystem::path::preferred_separator 那是operator/operator=,而不是operator/= 使用相对路径 std::filesystem::path("c:") 与绝对路径 std::filesystem::path("c:/") 有关系吗? "C:" 是驱动器相对路径。它解析为驱动器上的工作目录。加入“PosteClient.log”会产生“C:PosteClient.log”。如果驱动器上的工作目录是“C:\Spam”,那么解析的路径将是“C:\Spam\PosteClient.log”。 如果驱动器“C:”不是进程工作目录的驱动器,则系统从名为“=C:”的隐藏环境变量中获取每个驱动器的工作目录。如果该变量未定义,或引用驱动器上不存在的路径,则系统使用驱动器上的根目录。 【参考方案1】:

这是因为C:PosteClient.log 实际上是一个有效路径,并且很可能与C:\PosteClient.log不同。

关键是 Windows 进程维护每个驱动器的工作目录。

假设:

C:\THING\PosteClient.logD: 存在 cd C:\THING D:

现在,type C:PosteClient.log 可以正确找到您的文件,而 type C:\PosteClient.log 不能(也不应该)。

【讨论】:

以上是关于std::filesystem::path 的奇怪运算符/的主要内容,如果未能解决你的问题,请参考以下文章

std::filesystem current_path 返回根目录

有一个很奇怪的数学问题

Linux升级openssl时遇到的奇怪错误

很奇怪,谁知道这是啥编码???

奇怪的443端口?请专家释疑……

比较奇怪的数学问题 (很好理解)