use*_*520 5 c++ character-encoding c++20
考虑在 Linux 系统上运行的这段代码(编译器资源管理器链接):
#include <filesystem>
#include <cstdio>
int main()
{
try
{
const char8_t bad_path[] = {0xf0, u8'a', 0}; // invalid utf-8, 0xf0 expects continuation bytes
std::filesystem::path p(bad_path);
for (auto c : p.u8string())
{
printf("%X ", static_cast<uint8_t>(c));
}
}
catch (const std::exception& e)
{
printf("error: %s\n", e.what());
}
}
Run Code Online (Sandbox Code Playgroud)
它故意std::filesystem::path使用具有不正确的 UTF-8 编码的字符串构造一个对象(0xf0 开始一个 4 字节字符,但'a'不是连续字节;更多信息请参见此处)。
调用时u8string,不抛出异常;我发现这令人惊讶,因为cppreference 的文档指出:
- u8string() 的结果编码始终为 UTF-8。
检查LLVM 的 libcxx 的实现,我发现确实没有执行验证 - 内部保存的字符串std::filesystem::path只是复制到 a 中u8string并返回:
_LIBCPP_INLINE_VISIBILITY _VSTD::u8string u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); }
Run Code Online (Sandbox Code Playgroud)
GCC 实现 (libstdc++) 表现出相同的行为。
当然,这是一个人为的示例,因为我故意从无效字符串构建路径以使事情简单。但据我所知,Linux 内核/文件系统并不强制文件路径是有效的 UTF-8 字符串,因此我可能会在迭代目录时遇到类似“野外”的路径。
我是否可以得出这样的结论std::filesystem::path::u8string:实际上并不能保证返回有效的 UTF-8 字符串,无论文档如何规定?如果是这样,这个设计背后的动机是什么?
当前的 C++ 标准在fs.path.type.cvt中声明:
\n\n\nchar8_\xc2\xadt:编码为UTF-8。\n转换方法未指定。
\n
并且
\n\n\n如果要转换的编码没有源字符的表示形式,则转换后的字符(如果有)是未指定的。
\n
因此,简而言之,任何涉及组成路径的字节的实际解释的内容都是未指定的,这意味着实现可以自由地处理它们认为合适的无效数据。所以是的,std::filesystem::path::u8string()并不能真正保证返回有效的 UTF-8 字符串。
关于动机:标准没有提及。boost::filesystem但通过查看该标准的基础,人们可能会有所了解。文档指出:
\n\n当类路径函数参数类型与操作系统的路径 API 参数类型匹配时,不会执行任何转换,而是转换为指定的编码(例如 Unicode 编码之一)。这可以避免意外的后果等。
\n
我猜您使用的是 posix 系统,在这种情况下,底层操作系统 API很可能使用 UTF-8 或二进制文件名。因此,输入保持原样,以免遇到任何转换问题。\n另一方面,Windows 使用 UTF-16,因此需要在构造路径时转换字符串,从而在输入为无效的 UTF-8 编码 ( godbolt )。
\n| 归档时间: |
|
| 查看次数: |
1068 次 |
| 最近记录: |