mbrtowc的s == NULL情况的目的是什么?

R..*_*R.. 6 c standards multibyte language-lawyer

mbrtowc被指定为处理NULL用于指针s(多字节字符指针)参数,如下所示:

如果s是空指针,则mbrtowc()函数应等效于调用:

mbrtowc(NULL, "", 1, ps)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,将忽略参数pwc和n的值.

据我所知,这种用法基本上没用.如果ps没有存储任何部分转换的字符,则调用将返回0而没有副作用.如果ps正在存储的局部转换的字符,则因为'\0'是无效的,如一个多字节序列的下一个字节('\0'只能是一个字符串结束),则调用将返回(size_t)-1errno==EILSEQ.并ps处于未定义的状态.

预期的用法似乎是重置状态变量,特别是当NULL传递ps状态并且已经使用了内部状态时,类似于mbtowc有状态编码的行为,但就我所知,这在任何地方没有指定,并且它与mbrtowc存储部分转换字符的语义冲突(如果mbrtowc在潜在有效的初始子序列之后遇到0字节时重置状态,则无法检测到这种危险的无效序列).

如果mbrtowc指定仅在sis 时重置状态变量NULL,而不是在指向0字节时重置状态变量,则可能出现所需的状态重置行为,但这种行为将违反所写的标准.这是标准中的缺陷吗?据我所知,是绝对没有办法复位内部状态(使用时psNULL)一旦非法序列已经遇到过,因此没有正确的程序可以使用mbrtowcps==NULL.

Mic*_*urr 5

由于'\ 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;
}
Run Code Online (Sandbox Code Playgroud)

也许不是一个理想的情况,但我认为这表明它没有完全被打破,以至于无法使用.


标准引用:

5.2.1.2多字节字符

  • 多字节字符集可以具有依赖于状态的编码,其中每个多字节字符序列在初始移位状态下开始,并且当在序列中遇到特定的多字节字符时进入其他特定于语言环境的移位状态.在初始移位状态下,所有单字节字符都保留其通常的解释,并且不会改变移位状态.序列中后续字节的解释是当前移位状态的函数.

  • 所有位为零的字节应被解释为与移位状态无关的空字符.

  • 所有位为零的字节不应出现在多字节字符的第二个或后续字节中.

7.24.6.3.2/3 mbrtowc函数

如果相应的宽字符是空宽字符,则所描述的结果状态是初始转换状态