Неустранимая ошибка в преобразовании wchar_t * в char * - PullRequest
0 голосов
/ 11 февраля 2011

Вот код C, который преобразует строку wchar_t * в строку char *:

wchar_t *myXML = L"<test/>";
size_t length;
char *charString;
size_t i;
length = wcslen(myXML);
charString = (char *)malloc(length);
wcstombs_s(&i, charString, length, myXML, length);

Код компилируется, но при выполнении он обнаруживает фатальную ошибку в последней строке и прекращает работу.

Теперь, если я заменю последнюю строку этой:

wcstombs_s(&i, charString, length+1, myXML, length);

Я только добавил +1 к третьему аргументу. Тогда это прекрасно работает ...

Почему нужно добавить этот трюк? Или в моем коде есть изъян в другом месте?

Ответы [ 2 ]

4 голосов
/ 11 февраля 2011

Вам нужен один дополнительный байт для символа-терминатора '\0'.wcslen не включает это в длину, которую возвращает!

Чтобы сделать это правильно, вам нужно не просто передать length+1 в wcstombs_s, но также malloc:

charString = (char *)malloc(length+1);
wcstombs_s(&i, charString, length+1, myXML, length);

И даже тогда, я подозреваю, это не будет работать правильно.Не все широкие символы могут быть сопоставлены с одним char, поэтому для не-ASCII символов вам понадобится дополнительный пробел в многобайтовой строке.

2 голосов
/ 11 февраля 2011
DESCRIPTION
       The wcslen() function is the wide-character
       equivalent of the strlen(3) function.  It determines
       the length of the wide-character string pointed to by
       s, not including the terminating L'\0' character.

Хитрость в том, что вы должны всегда искать код вида:

string = malloc(len);

очень подозрительно, потому что и wcslen(3) и strlen(3) возвращают длину строки без нулевого байта , и malloc(3) должен выделять пространство с этим байтом. С отстой иногда.

Поэтому каждый раз, когда вы видите string = malloc(len);, а не string = malloc(len+1);, очень внимательно читайте, как присваивается len.

char String = (char *)malloc(length + 1);

Должен сделать трюк. :)

EDIT

Лучше было бы спросить wcstombs() о размере, выделяемом в первую очередь:

size_t len = wcstombs(NULL,src,0) + 1;
char *dest = malloc(len);
len = wcstombs(dest, src, len);
if (len == -1) /* handle error */ ...

+1 выделяет ascii nul, а wcstombs() сообщит, сколько памяти требуется для преобразования. Он выполнит преобразование дважды , один раз для отслеживания требуемой памяти, а затем один раз для сохранения результата, но поддерживать его будет НАМНОГО проще. Во второй раз, когда он сохраняет результат, он записывает не более len байтов , включая ascii nul .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...