【问题标题】:Is casting strings from `wchar_t` to `char16_t` legal if encoding and width is the same?如果编码和宽度相同,将字符串从 `wchar_t` 转换为 `char16_t` 是否合法?
【发布时间】:2022-02-02 19:46:50
【问题描述】:

在 Windows 上,wchar_t 是一个 UTF-16(LE) 格式的字符,在大多数情况下,它等同于 char16_t。然而,这两种字符类型在 C++ 类型系统中仍然是不同的类型——这让我不确定根据 C++ 标准在这两种字符类型的 sequences 之间进行转换是否合法。

我的问题是:在 C++17 中,执行以下强制转换并读取转换后的指针是否合法:

  • reinterpret_cast<const wchar_t*>(char16_ptr) 其中decltype(char16_ptr)const char16_t*,并且
  • reinterpret_cast<const char16_t*>(wchar_ptr) 其中decltype(wchar_ptr)const wchar_t*

就本问题而言,假设如下:

  • sizeof(wchar_t) == sizeof(char16_t),和
  • wchar_t 的格式与 char16_t 相同(在 Windows 上也是如此)

基本上,这是否违反了严格别名?

我的理解是 cast 本身是有效的,这要归功于 [expr.reinterpret.cast]/7,但是由于类型被不是 char 的东西所别名,因此不能安全地使用转换的结果,unsigned char,或std::byte。这种解释正确吗?


注意:关于wchar_tchar16_t 的其他问题已被提出,但这个问题不是尽我所能告诉。值得注意的是,问题“Are wchar_t and char16_t the same on Windows?”实际上在指针之间执行了reinterpret_cast,但没有一个答案实际上首先说明了这种转换是否合法。

【问题讨论】:

  • 从指向一种类型的指针转​​换为指向另一种类型的指针是完全合法的。您可能遇到的唯一问题是在 Linux 上编译 wchar_tchar32_t 相同,您最终会认为您在字符串结尾之前遇到了空终止符。
  • 转换是完全合法的,但这并不意味着使用(即读取、写入)指向的对象是合法的;这可能违反了严格混叠——我认为是这样。问题是这是否违法,或者是否合法。
  • 当心! Windows 上的 wchar_t 未签名。

标签: c++ c++17 language-lawyer undefined-behavior strict-aliasing


【解决方案1】:

你已经知道答案了:strictly speaking, no

wchar_t 不是char16_t。两者都不是从另一个派生的。两者都不相似。两者都不是另一个的签名/未签名版本。两者都不是包含另一个的聚合。而且它们都不是字节类型(char 等)。

因此,您无法通过指向 char16_t 的指针/引用来访问 wchar_t

如果您的目标是严格避免严格的别名,您将不得不将数据复制到不同的对象。 有效的,假设它们都具有相同的表示。

【讨论】:

  • 这就是我所担心的;太糟糕了。由于这些值可以轻松复制,我不确定布局兼容性是否有任何灵活性。我想我得std::copy
猜你喜欢
  • 1970-01-01
  • 2018-09-02
  • 2014-11-12
  • 1970-01-01
  • 1970-01-01
  • 2013-05-07
  • 2011-02-03
  • 2012-09-09
相关资源
最近更新 更多