Почему я не могу преобразовать многобайтовую строку в широкую строку?mbsrtowcs завершается ошибкой с EILSEQ, хотя mbstring кажется действительным - PullRequest
0 голосов
/ 23 ноября 2018

Пожалуйста, посмотрите этот фрагмент, который я написал, который должен просто преобразовать многобайтовую строку (полученную из stdin) в широкую строку.Прочитав документацию mbsrtowcs и mbstate_t из cppreference, я подумал, что она действительна:

#include <stdio.h>
#include <wchar.h>
#include <errno.h>
#include <stdlib.h>
#include <error.h>

int main()
{
        char *s = NULL; size_t n = 0; errno = 0;
        ssize_t sn = getline(&s, &n, stdin);
        if(sn == -1 && errno != 0)
                error(EXIT_FAILURE, errno, "getline");
        if(sn == -1 && errno == 0) // EOF
                return EXIT_SUCCESS;

        // determine how big should be the allocated buffer
        const char* cs = s; mbstate_t st = {0}; // cs to avoid comp. warnings
        size_t wn = mbsrtowcs(NULL, &cs, 0, &st);
        if(wn == (size_t)-1)
                error(EXIT_FAILURE, errno, "first mbsrtowcs");

        wchar_t* ws = malloc((wn+1) * sizeof(wchar_t));
        if(ws == NULL)
                error(EXIT_FAILURE, errno, "malloc");

        // finally convert the multibyte string to wide string
        st = (mbstate_t){0};
        if(mbsrtowcs(ws, &cs, wn+1, &st) == (size_t)-1)
                error(EXIT_FAILURE, errno, "second mbsrtowcs");

        if(printf("%ls", ws) < 0)
                error(EXIT_FAILURE, errno, "printf");

        return EXIT_SUCCESS;
}

Да, это работает для строк ASCII.НО причина, по которой я пытаюсь работать со строками не-ASCII, заключается в том, что я хотел бы поддерживать диакритические знаки за пределами таблицы ASCII! И это не сработает для тех .Первый вызов mbsrtowcs завершается с EILSEQ, что указывает на недопустимость многобайтовой строки.Но, как ни странно, проверка его с помощью gdb кажется действительной!(поскольку gdb отображает его правильно).Пожалуйста, просмотрите эффект от подачи этого фрагмента не-ASCII-строки и gdb со следующим:

m@m-X555LJ:~/wtfdir$ gcc -g -o wtf wtf.c
m@m-X555LJ:~/wtfdir$ ./wtf
asa
asa
m@m-X555LJ:~/wtfdir$ ./wtf
ąsa
./wtf: first mbsrtowcs: Invalid or incomplete multibyte or wide character
m@m-X555LJ:~/wtfdir$ gdb ./wtf
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./wtf...done.
(gdb) break 18
Breakpoint 1 at 0x93b: file wtf.c, line 18.
(gdb) r
Starting program: /home/m/wtfdir/wtf 
ąsa

Breakpoint 1, main () at wtf.c:18
18          size_t wn = mbsrtowcs(NULL, &cs, 0, &st);
(gdb) p cs
$1 = 0x555555756260 "ąsa\n"
(gdb) c
Continuing.
/home/m/wtfdir/wtf: first mbsrtowcs: Invalid or incomplete multibyte or wide character
[Inferior 1 (process 5612) exited with code 01]
(gdb) quit

Если это имеет значение, я нахожусь в Linux, и кодировка локали выглядит как UTF8:

m@m-X555LJ:~$ locale charmap
UTF-8

(вот почему я ожидал, что это сработает, тривиальные программы, такие как printf("ąsa\n");, как правило, работают для меня на Linux, но не на Windows)

Чего мне не хватает?что я делаю не так?

...