mbrtowc
指定用于处理 s
(多字节字符指针)参数的 NULL
指针,如下所示:
If s is a null pointer, the mbrtowc() function shall be equivalent to the call:
mbrtowc(NULL, "", 1, ps)
In this case, the values of the arguments pwc and n are ignored.
据我所知,这种用法在很大程度上是无用的。如果 ps
没有存储任何部分转换的字符,调用将简单地返回 0 而没有副作用。如果 ps
正在存储一个部分转换的字符,那么由于 '\0'
作为多字节序列中的下一个字节是无效的 ('\0'
只能是字符串终止符),调用将返回 (size_t)-1
和 errno==EILSEQ
。并使 ps
处于未定义状态。
预期的用途似乎是重置状态变量,特别是当 NULL
被传递给 ps
并且内部状态已被使用时,类似于 mbtowc
的状态编码行为,但据我所知,这未在任何地方指定,并且它与 mbrtowc
的存储语义冲突部分转换的字符(如果 mbrtowc
在可能有效的初始子序列后遇到 0 字节时重置状态,它将无法检测到这个危险的无效序列)。
如果 mbrtowc
被指定为仅当 s
为 NULL
时重置状态变量,而不是当它指向 0 字节时,a理想的状态重置行为是可能的,但这种行为会违反书面标准。这是标准的缺陷吗?据我所知,一旦遇到非法序列,绝对没有办法重置内部状态(当 ps
为 NULL
时使用),因此没有正确的程序可以使用 mbrtowc
和 ps==NULL
。
最佳答案
由于无论移位状态如何,'\0' 字节都必须转换为空宽字符(5.2.1.2 多字节字符),并且 mbrtowc()
函数被指定为在以下情况下重置移位状态它转换为宽空字符(7.24.6.3.2/3 的 mbrtowc 函数),调用 mbrtowc( NULL, "", 1, ps)
将重置存储在 中的移位状态
。如果调用 ps
指向的 mbstate_tmbrtowc( NULL, "", 1, NULL)
以使用库的内部 mbstate_t
对象,它将重置为初始状态。有关标准相关部分的引用,请参阅答案的末尾。
我在 C 标准多字节转换函数方面绝对不是特别有经验(我对这种事情的经验一直是使用 Win32 API 进行转换)。
如果 mbrtowc()
处理一个被 0 字节截短的“不完整字符”,它应该返回 (size_t)(-1)
以指示无效的多字节char(从而检测到您描述的危险情况)。在那种情况下,转换/转换状态是未指定的(我认为你基本上已经被那个字符串所淹没了)。尝试转换但包含 '\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 多字节字符
A multibyte character set may have a state-dependent encoding, wherein each sequence of multibyte characters begins in an initial shift state and enters other locale-specific shift states when specific multibyte characters are encountered in the sequence. While in the initial shift state, all single-byte characters retain their usual interpretation and do not alter the shift state. The interpretation for subsequent bytes in the sequence is a function of the current shift state.
A byte with all bits zero shall be interpreted as a null character independent of shift state.
- A byte with all bits zero shall not occur in the second or subsequent bytes of a multibyte character.
7.24.6.3.2/3 mbrtowc函数
If the corresponding wide character is the null wide character, the resulting state described is the initial conversion state
关于c - mbrtowc 的 s==NULL 案例的目的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4709498/