C++ std::codecvt_utf8方面存在问题
下面是一段代码,它使用C++ std::codecvt_utf8方面存在问题,c++,visual-studio,utf-8,locale,codecvt,C++,Visual Studio,Utf 8,Locale,Codecvt,下面是一段代码,它使用std::codevt_utf8facet将wchar_t转换为UTF-8。在Visual Studio 2012中,我的期望没有得到满足(请参见代码末尾的条件)。我的期望错了吗?为什么?或者这是Visual Studio 2012库的问题 #include <locale> #include <codecvt> #include <cstdlib> int main () { std::mbstate_t state = st
std::codevt_utf8
facet将wchar_t
转换为UTF-8。在Visual Studio 2012中,我的期望没有得到满足(请参见代码末尾的条件)。我的期望错了吗?为什么?或者这是Visual Studio 2012库的问题
#include <locale>
#include <codecvt>
#include <cstdlib>
int main ()
{
std::mbstate_t state = std::mbstate_t ();
std::locale loc (std::locale (), new std::codecvt_utf8<wchar_t>);
typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
codecvt_type const & cvt = std::use_facet<codecvt_type> (loc);
wchar_t ch = L'\u5FC3';
wchar_t const * from_first = &ch;
wchar_t const * from_mid = &ch;
wchar_t const * from_end = from_first + 1;
char out_buf[1];
char * out_first = out_buf;
char * out_mid = out_buf;
char * out_end = out_buf + 1;
std::codecvt_base::result cvt_res
= cvt.out (state, from_first, from_end, from_mid,
out_first, out_end, out_mid);
// This is what I expect:
if (cvt_res == std::codecvt_base::partial
&& out_mid == out_end
&& state != 0)
;
else
abort ();
}
#包括
#包括
#包括
int main()
{
std::mbstate_t state=std::mbstate_t();
std::locale loc(std::locale(),新的std::codevt_utf8);
typedef std::codevt codevt_type;
codevt_type const&cvt=std::use_facet(loc);
wchar_t ch=L'\u5FC3';
wchar_t const*from_first=&ch;
wchar_t const*from_mid=&ch;
wchar_t const*from_end=from_first+1;
char out_buf[1];
char*out\u first=out\u buf;
char*out\u mid=out\u buf;
char*out\u end=out\u buf+1;
std::codecvt_base::result cvt_res
=cvt.out(状态,从\u开始,从\u结束,从\u中间,
先出、后出、中出);
//这就是我所期望的:
如果(cvt_res==std::codevt_base::partial
&&out\u mid==out\u end
&&状态!=0)
;
其他的
中止();
}
这里的期望是out()
函数一次输出一个字节的UTF-8转换,但是上面的if
条件中间在Visual Studio 2012中为false
更新
失败的是
out\u mid==out\u end
和状态!=0
条件。基本上,我希望至少产生一个字节,并且UTF-8序列的下一个字节可产生的必要状态将存储在state
变量中。虽然没有直接引用它,但我认为这是std::codevt::out
的最合乎逻辑的行为。考虑下面的场景:
- 您使用的
方式与以前相同-不将任何字符(可能不知道)翻译到std::codecvt::out
out\buf
- 现在,您需要将另一个字符串转换为
(再次使用out\u buf
)以便它附加已经在其中的内容std::codecvt::out
- 为此,您决定使用
,因为您知道它直接指向您在第一步翻译的字符串之后buf_mid
- 现在,如果
按照您的期望工作(std::codecvt::out
指向第一个字符之后的字符),那么您的buf_-mid
的第一个字符将永远不会被写入,这与您在本例中希望/期望的不完全相同out_-buf
extern\u type*&to\u next
(std::codecvt::out的最后一个参数)在这里作为您离开的位置的参考-因此您知道在哪里继续-这在您的情况下确实与您开始的位置相同(extern\u type*to
)参数
codecvt::do_out
的partial
返回代码的标准描述正好说明了这一点:
表83:
部分
并非所有源字符都已转换
在22.4.1.4.2[locale.codecvt.virtuals]/5中:
返回:枚举值,如表83所示。如果返回值partial
(from\u next==from\u end),则表示目标序列
没有吸收所有可用的目标元素,或者在生成另一个目标元素之前需要额外的源元素
在您的例子中,并非所有(零)源字符都被转换,从技术上讲,输出序列的内容(句子中的'if'子句没有输入)没有任何意义,但一般来说,“目标序列没有吸收所有可用的目标元素”,这里谈论的是有效的多字节字符。它们是由codevt\u utf8产生的多字节字符序列的元素
最好有一个更明确的标准措辞,但这里有两个间接证据:
一:旧C的宽到多字节转换函数std::wcsrtombs
(其特定于语言环境的变体通常由系统提供的语言环境的现有实现codevt::do_out
调用)定义如下:
当下一个多字节字符将超过要存储到dst指向的数组中的len总字节数限制时,转换停止[…]
第二,看看现有的codecvt\u utf8
:您已经了解了微软的,下面是libc++中的内容:codecvt\u utf8::do\u out
这里在Windows上调用ucs2\u到utf8
,在其他系统上调用ucs4\u到utf8
,在ucs2\u到utf8(我的评论):
else if(wc<0x0800)
{
//无关
}
else//if(wc 12));
*to_nxt++=静态_cast(0x80 |((wc&0x0FC0)>>6));
*to_nxt++=静态_cast(0x80 |(wc&0x003F));
}
如果输出序列不能容纳使用一个输入宽字符产生的多字节字符,则不会写入任何内容。还有
状态
变量/参数,该变量/参数应为实现提供有关转换状态的一些信息。您在上面描述的内容是,在对要附加的字符串再次调用codecvt::out()
之前,应该通过状态和调用(如果输出缓冲区只有一个字节长,则可能再次在循环中调用)来处理的问题。@wilx这是一个很好的观点。Microsoft是否答复了您的问题?(我在他们的网站上看到了你的问题)除了两条自动消息之外,我还没有收到任何反应。我不知道你想反驳我的期望的哪一部分。你能澄清一下吗?@wilx你希望函数产生一个字节,而不是一个多字节
else if (wc < 0x0800)
{
// not relevant
}
else // if (wc <= 0xFFFF)
{
if (to_end-to_nxt < 3)
return codecvt_base::partial; // <- look here
*to_nxt++ = static_cast<uint8_t>(0xE0 | (wc >> 12));
*to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
*to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x003F));
}