由于 '\0' 字节必须转换为空宽字符而不管移位状态(5.2.1.2 多字节字符),并且mbrtowc()
指定函数在转换为宽空字符时重置移位状态(7.24.6.3.2 /3 mbrtowc 函数),调用mbrtowc( NULL, "", 1, ps)
将重置存储在mbstate_t
指向的移位状态ps
。如果mbrtowc( NULL, "", 1, NULL)
被调用使用库的内部mbstate_t
对象,它将被重置为初始状态。有关标准相关位的引用,请参见答案的末尾。
我对 C 标准多字节转换函数并不是特别有经验(我对这种事情的经验是使用 Win32 API 进行转换)。
如果mbrtowc()
处理一个被 0 字节缩短的“不完整字符”,它应该返回(size_t)(-1)
以指示无效的多字节字符(从而检测您描述的危险情况)。在那种情况下,转换/转换状态是未指定的(我认为你基本上已经为那个字符串而烦恼了)。尝试转换但包含 a 的多字节“序列”'\0'
是无效的,并且对后续数据始终有效。如果'\0
' 不打算成为转换序列的一部分,那么它不应该包含在可用于处理的字节数中。
如果您处于可能获得部分多字节字符的额外后续字节(例如来自网络流)的情况,n
则为部分多字节字符传递的不应包含 0 字节,因此您将获得(size_t)(-2)
回来。在这种情况下,如果您'\0'
在部分转换的中间经过一段时间,您将失去存在错误的事实,并且作为副作用重置mbstate_t
正在使用的状态(无论是您自己的还是正在使用的内部状态,因为您为 ) 传入了一个 NULL 指针ps
。我想我在这里基本上重申了你的问题。
但是我认为可以检测和处理这种情况,但不幸的是它需要自己跟踪一些状态:
#define MB_ERROR ((size_t)(-1))
#define MB_PARTIAL ((size_t)(-2))
// function to get a stream of multibyte characters from somewhere
int get_next(void);
int bar(void)
{
char c;
wchar_t wc;
mbstate_t state = {0};
int in_partial_convert = 0;
while ((c = get_next()) != EOF)
{
size_t result = mbrtowc( &wc, &c, 1, &state);
switch (result) {
case MB_ERROR:
// this multibyte char is invalid
return -1;
case MB_PARTIAL:
// do nothing yet, we need more data
// but remember that we're in this state
in_partial_convert = 1;
break;
case 1:
// output the competed wide char
in_partial_convert = 0; // no longer in the middle of a conversion
putwchar(wc);
break;
case 0:
if (in_partial_convert) {
// this 'last' multibyte char was mal-formed
// return an error condidtion
return -1;
}
// end of the multibyte string
// we'll handle similar to EOF
return 0;
}
}
return 0;
}
也许不是一个理想的情况,但我认为这表明它没有完全损坏,无法使用。
标准引用:
5.2.1.2 多字节字符
7.24.6.3.2/3 mbrtowc 函数
如果对应的宽字符是空宽字符,则描述的结果状态是初始转换状态