指定mbrtowc
来处理NULL
(多字节字符指针)参数的s
指针,如下所示:
据我所知,这种用法在很大程度上是没有用的。如果ps
没有存储任何部分转换的字符,则该调用将简单地返回0而没有副作用。如果ps
存储了部分转换的字符,则由于'\0'
无效,不能作为多字节序列中的下一个字节('\0'
只能是字符串终止符),因此该调用将返回(size_t)-1
和errno==EILSEQ
。并将ps
保留为未定义状态。
预期的用途似乎是重置状态变量,尤其是当为NULL
传递了ps
并使用了内部状态时,类似于mbtowc
具有状态编码的行为,但是据我所知,并没有在任何地方指定,并且与mbrtowc
存储部分转换的字符的语义相冲突(如果在可能有效的初始子序列之后遇到0字节时mbrtowc
处于重置状态,则将无法检测到此危险的无效序列)。
如果仅当mbrtowc
为s
时才指定NULL
重置状态变量,而当它指向0字节时才指定重置状态变量,则可能会发生理想的状态重置行为,但这种行为会违反所编写的标准。这是标准的缺陷吗?据我所知,一旦遇到非法序列,绝对没有办法重置内部状态(当ps
为NULL
时使用),因此,没有正确的程序可以将mbrtowc
与ps==NULL
一起使用。
最佳答案
由于无论移位状态如何,'\0'字节都必须转换为null宽字符(5.2.1.2多字节字符),并且指定了mbrtowc()
函数以在转换为宽null字符(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)
指示无效的多字节字符(从而检测到您描述的危险情况)。在那种情况下,转换/移位状态是未指定的(我认为您基本上是在为该字符串缓冲)。尝试进行转换但包含'\0'
的多字节“序列”无效,并且以后对任何数据都将有效。如果'\0
'不打算成为转换后的序列的一部分,则不应将其包含在可用于处理的字节数中。
如果您处在可能会为部分多字节字符(例如从网络流)获得更多后续字节的情况下,则为部分多字节字符传递的n
不应包含0字节,因此您将获得返回了(size_t)(-2)
。在这种情况下,如果您在部分转换过程中传递了'\0'
,则会丢失以下事实:出现错误,并且由于副作用,重置了正在使用的mbstate_t
状态(无论是您自己的还是内部的之所以使用,是因为您为ps
传递了NULL指针。我想我是在这里重申您的问题。
但是,我认为有可能检测并处理这种情况,但不幸的是,这需要您自己跟踪某些状态:
#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函数