指定mbrtowc来处理NULL(多字节字符指针)参数的s指针,如下所示:

据我所知,这种用法在很大程度上是没有用的。如果ps没有存储任何部分转换的字符,则该调用将简单地返回0而没有副作用。如果ps存储了部分转换的字符,则由于'\0'无效,不能作为多字节序列中的下一个字节('\0'只能是字符串终止符),因此该调用将返回(size_t)-1errno==EILSEQ。并将ps保留为未定义状态。
预期的用途似乎是重置状态变量,尤其是当为NULL传递了ps并使用了内部状态时,类似于mbtowc具有状态编码的行为,但是据我所知,并没有在任何地方指定,并且与mbrtowc存储部分转换的字符的语义相冲突(如果在可能有效的初始子序列之后遇到0字节时mbrtowc处于重置状态,则将无法检测到此危险的无效序列)。
如果仅当mbrtowcs时才指定NULL重置状态变量,而当它指向0字节时才指定重置状态变量,则可能会发生理想的状态重置行为,但这种行为会违反所编写的标准。这是标准的缺陷吗?据我所知,一旦遇到非法序列,绝对没有办法重置内部状态(当psNULL时使用),因此,没有正确的程序可以将mbrtowcps==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函数

10-04 20:58