C ++标准是否要求对wchar_t进行编码?

时间:2016-08-04 14:49:32

标签: c++ c++11 unicode wchar-t

以下是我的2014年标准草案N4140

的一些摘录
  

22.5标准代码转换方面[locale.stdcvt]

     

3对于三个代码转换方面codecvt_utf8codecvt_utf16codecvt_utf8_utf16中的每一个:   (3.1) - Elem是宽字符类型,例如wchar_tchar16_tchar32_t

     

4对于方面codecvt_utf8
  (4.1) - 方面应在程序内转换UTF-8多字节序列和UCS2或UCS4(取决于Elem的大小)。

这两段的一种解释是wchar_t必须编码为UCS2或UCS4。我不喜欢它,因为如果它是真的,我们在图书馆描述深处埋藏了一种重要的语言属性。我试图找到一个更直接的声明这个属性,但无济于事。

wchar_t编码不需要是UCS2或UCS4的另一种解释,以及在{0}} codecvt_utf8不适合wchar_t工作的实现。我也不喜欢这种解释,因为如果它是真的,并且charwchar_t本机编码都不是Unicode,那么它似乎不是一种方式可以在这些本机编码和Unicode之间进行便携式转换。

这两种解释中哪一种是正确的?还有一个我忽略了吗?

澄清我不会询问有关wchar_t是否适合软件开发的一般意见,或wchar_t可以从其他地方获得的属性。我对标准的这两个特定段落感兴趣。我试图了解这些特定段落带来或不带来的含义。

澄清2 。如果4.1表示&#34; facet将在UTF-8多字节序列和UCS2或UCS4 之间转换,或者当前全局语言环境对wchar_t施加的任何编码&#34;没有问题。它没有。它说的是什么。看来如果使用std::codecvt_utf8<wchar_t>,最终会有一堆wchar_t编码为UCS2或UCS4,而不管当前的全局区域设置如何。 (无法为codecvt_utf8)指定区域设置或任何字符转换方面。所以这个问题可以这样重写:转换结果是否可以直接用于当前的全局语言环境(和/或任何可能的语言环境),用于输出,wctype查询等等?如果没有,那么可用于? (如果上面的第二种解释是正确的,答案似乎是&#34;没有&#34;)。

7 个答案:

答案 0 :(得分:6)

wchar_t只是一个完整的字面值。它有最小值,最大值等。

其尺寸不受标准规定。

如果足够大,您可以将UCS-2或UCS-4数据存储在wchar_t的缓冲区中。无论您使用何种系统,都是如此,因为UCS-2和UCS-4以及UTF-16和UTF-32只是序列中排列的整数值的描述。

在C ++ 11中,有std个API可以读取或写入数据,假设它具有这些编码。在C ++ 03中,有些API使用当前语言环境读取或写入数据。

  

22.5标准代码转换方面[locale.stdcvt]

     

3对于三个代码转换方面中的每一个,codecvt_utf8,codecvt_utf16和codecvt_utf8_utf16:

     

(3.1) - Elem是宽字符类型,例如wchar_t,char16_t或char32_t。

     

4对于facet codecvt_utf8:

     

(4.1) - 方面应在程序内转换UTF-8多字节序列和UCS2或UCS4(取决于Elem的大小)。

所以这里codecvt_utf8_utf16一方面处理utf8,另一方面处理UCS2或UCS4(取决于Elem有多大)。它确实转换。

Elem(宽字符)被假定为在UCS2或UCS4中编码,具体取决于它的大小。

这并不意味着wchar_t被编码,只是意味着此操作将wchar_t解释为编码为

UCS2或UCS4如何进入Elem并不是标准所关心的部分。也许你用十六进制常量设置它。也许你是从io中读到的。也许你是在飞行中计算出来的。也许你使用了一个高质量的随机数发生器。也许你将ascii字符串的位值加在一起。也许你计算了月亮将地球日改变1秒所需的秒数的log*的定点近似值。 不是这些段落的问题。这些段落只是强制要求如何修改和解释位。

在其他情况下也有类似的说法。这并不强制wchar_t具有哪种格式。它只是说明了这些方面如何解释wchar_tchar16_tchar32_tchar8_t(阅读或写作)。

wchar_t交互的其他方式使用不同的方法来强制解释wchar_t的值。

例如,

iswalpha使用(全局)区域设置来解释wchar_t。在某些本地人中,wchar_t可能是UCS2。在其他情况下,它可能是一些疯狂的cthulian编码,其细节使您能够从空间中看到新的颜色。

要明确:编码不是数据或位的属性。编码是数据解释的属性。通常只有一个正确的合理的数据解释,但数据本身就是位。

C ++标准不强制要求wchar_t中存储的内容。它确实要求某些操作解释wchar_t的内容。该部分描述了某些方面如何解释wchar_t中的数据。

答案 1 :(得分:5)

没有

a:hover { color: green; } 只需要保存编译器支持的最大语言环境。从理论上讲,它可以适用于char。

  

类型wchar_t是一种不同的类型,其值可以表示支持的语言环境(22.3.1)中指定的最大扩展字符集的所有成员的不同代码。

     

- C ++ [basic.fundamental] 3.9.1 / 5

因此它甚至不需要支持Unicode

  

wchar_t的宽度是特定于编译器的,可以小到8位。因此,需要可以在任何C或C ++编译器上移植的程序不应使用wchar_t来存储Unicode文本。 wchar_t类型用于存储编译器定义的宽字符,在某些编译器中可能是Unicode字符。

     

ISO / IEC 10646:2003 Unicode标准4.0

答案 2 :(得分:3)

让我们区分使用wchar_t前缀构建的L和字符串文字。

wchar_t只是一个整数类型,可能大于char

使用L前缀的字符串文字将使用wchar_t个字符生成字符串。究竟是什么意味着依赖于实现。不要求此类文字使用任何特定编码。他们可能会使用UTF-16,UTF-32或其他与Unicode无关的东西。

因此,如果您希望在所有平台上以Unicode格式编码保证的字符串文字,请使用u8u或{{1}字符串文字的前缀。

  

这两段的一种解释是wchar_t必须编码为UCS2或UCS4。

不,这不是一个有效的解释。 U 没有编码;它只是一种类型。它是数据,它被编码。前缀为wchar_t的字符串文字可能会也可能不会在UCS2或UCS4中编码。

如果您提供L一串codecvt_utf8个字符串,这些字符串在UCS2或UCS4中编码(适用于wchar_t),那么它将起作用。但不是因为sizeof(wchar_t);它只能起作用,因为你提供的数据是正确编码的。

  

如果4.1表示“该方面应在UTF-8多字节序列和UCS2或UCS4之间进行转换,或者当前全局语言环境对wchar_t施加的任何编码”都没有问题。

这些wchar_t方面的重点是执行与区域设置无关的转换。如果您想要与区域设置相关的转换,则不应使用它们。您应该使用全局codecvt_*方面。

答案 3 :(得分:1)

Microsoft列出了您的第一个结论,他们列举了可能的选项,并注意到UTF-16虽然“广泛用作[sic]”但不是有效的编码。

QNX也使用了相同的措辞,它指出了措辞的来源:QNX和Microsoft都从Dinkumware派生了他们的标准库实现。

现在,正如它发生的那样,Dinkumware也是引入这些类的N2401的作者。所以我要支持他们。

答案 4 :(得分:1)

由于Elem可以是wchar_tchar16_tchar32_t,因此第4.1条没有说明所需的wchar_t编码。它说明了所执行的转换。

根据措辞,很明显转换是在UTF-8和UCS-2或UCS-4之间,具体取决于Elem的大小。因此,如果wchar_t是16位,则转换将使用UCS-2,如果是32位,则转换为UCS-4。

为什么标准提到UCS-2和UCS-4而不是UTF-16和UTF-32?因为codecvt_utf8会将多字节UTF8转换为单个宽字符:

  • UCS-2是unicode的子集,但与{1}}相反,与UTF-16相反
  • UCS-4现在与UTF-32相同(但是看着越来越多的表情符号,也许有一天不能有足够的32位,你会得到一个UTF-64和UTF32替代品codecvt_utf8
  • 不支持的对

虽然,我不清楚会发生什么,如果UTF-8文本包含的序列对应于用于接收{0}的UCS-2中不可用的unicode字符。

答案 5 :(得分:1)

你的解释都不正确。标准并不要求只有一个wchar_t编码,就像它不需要单char个编码一样。 codecvt_utf8方面必须在UTF-8和UCS-2或UCS-4之间进行转换。 在任何语言环境中,不支持UTF-8,UCS-2和UCS-4作为字符集。

如果Elem的类型为wchar_t并且不足以存储UCS-2值,则codecvt_utf8方面的转换操作未定义,因为标准没有说明那种情况会发生什么。如果它足够大(或者如果你想证明标准要求它必须足够大)那么它只是实现定义UCS-2或UCS-4 wchar_t值是否生成了facet生成或使用的编码与定义wchar_t编码的任何区域设置兼容。

答案 6 :(得分:0)

第一种解释是有条件的。

如果定义了__STDC_ISO_10646__宏(从C导入),则wchar_t是某个版本的Unicode的超集。

  

__STDC_ISO_10646__
  yyyymmL形式的整数文字(例如,199712L)。如果定义了这个符号,那么每一个   Unicode所需集中的字符,当存储在类型为wchar_t的对象中时,具有相同的值   作为该角色的短标识符。 Unicode必需集包含所有字符   由ISO / IEC 10646定义,以及所指定的所有修正和技术勘误   年和月。

似乎如果定义了宏,可以假设某种UCS4。 (不是UCS2,因为ISO 10646从未有过16位版本; ISO 10646的第一个版本对应于Unicode 2.0)。

因此,如果定义了宏,那么

  • 有一个“原生”wchar_t编码
  • 它是某些版本的UCS4
  • 的超集
  • codecvt_utf8<wchar_t>提供的转换与此原始编码兼容

如果未定义宏,则不需要保留这些内容。

还有__STDC_UTF_16____STDC_UTF_32__,但C ++标准没有说出它们的含义。 C标准表示它们分别表示char16_tchar32_t的UTF-16和UTF-32编码,但在C ++中,这些编码总是被使用。

顺便提一下,函数mbrtoc32c32rtombchar序列和char32_t序列之间来回转换。在C中,如果定义了__STDC_UTF_32__,它们只使用UTF-32,但在C ++中,UTF-32始终用于char32_t。因此,即使__STDC_ISO_10646__ 定义,也应该可以通过从UTF-8转换为UTF-32来在UTF-8和wchar_t之间进行转换。将char32_t编码为原生编码char到本机编码wchar_t,但我害怕这些复杂的东西。