WideCharToMultiByte конвертирует строку, но добавляет мусор

175
05 июля 2018, 13:00

Не понимаю, каким образом в строку с результатом попадет мусор, и откуда.

template <class T>
T* malloc(size_t size)
{
    return static_cast<T*>(malloc(size));
}
void utf8_encode(const wchar_t* input, char** output)
{
    int str_len = wcslen(input);
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, input, str_len, nullptr, 0, 0, 0);
    *output = malloc<char>(size_needed);
    memset(*output, 0 , size_needed);
    WideCharToMultiByte(CP_UTF8, 0, input, str_len, *output, size_needed, 0, 0);
}

int main()
{
    const wchar_t buffer[] = L"String contain any wide characters こんにちは";
    char* result = nullptr;
    utf8_encode(buffer, &result);
    printf("%s", result);
    free(result);
}
Answer 1

WideCharToMultiByte конвертирует не ASCII-z строки, а массив. На выходе функции - идет char (байт). это означает что если вы конвертируете строку длинной size_needed - то она сконвертируется, но вам нужен +1 символ, если стока должна быть не "массивом", а ASCII-z, т.к. большинство функций работает именно с ASCII-z. В данном случае я бы сделал так

*output = malloc<char>(size_needed + 1); /*Добавить 1*/
//memset(*output, 0 , size_needed); это лишнее
WideCharToMultiByte(CP_UTF8, 0, input, str_len, *output, size_needed, 0, 0);
(*output)[size_needed] = 0; /*Добавляем ноль*/

Если вам строка 2 - нравится, то строку 4 можно не писать.

Для MultiByteToWideChar длинна символа будет 2, поэтому будет malloc<wchar_t>(size_needed + 2) (если size_needed-правильный размер).

P.S. Вижу преобразование кодировок, от себя добавлю. Если нужна конвертация с юникода в ANSI/OEM есть интересный короткий вариант wsprintfA(*output,"%ls",input) и назад wsprintfW(*output,L"%hs",input)

Answer 2

WideCharToMultiByte имеет два режима работы: с массивом указанной длины и с оканчивающейся нулем строкой. Явно указывая длину входного массива str_len активируется первый режим, а для активации второго вместо длины следует передать -1, тогда функция вернет требуемый размер буфера включая ноль на конце и корректно его поставит во время конвертации. Соответственно считать длину строки самостоятельно не нужно, однако следует проверять возвращаемые значения перед использованием:

char * p_output{};
int const buffer_capacity{::WideCharToMultiByte(CP_UTF8, 0, input, -1, nullptr, 0, 0, 0)};
if(0 < buffer_capacity)
{
    p_output = malloc<char>(buffer_capacity);
    if(p_output)
    {
        [[maybe_unused]] int const bytes_written{::WideCharToMultiByte(CP_UTF8, 0, input, -1, p_output, buffer_capacity, 0, 0)};
        assert(bytes_written == buffer_capacity);
        assert('\0' == p_output[buffer_capacity - 1]);
    }
}
*output = p_output;
READ ALSO
Парсинг курса валют Visual Studio c++

Парсинг курса валют Visual Studio c++

Подскажите пожалуйста как парсить курс валют с определённого сайта на с++ ( visual studio 2012) Windows Forms Может быть есть книги с гайдами?

191
Проблемы верстки

Проблемы верстки

Дали мне мне лендинг править а тут после футера нехилый отступ с пустотойВсе элементы находятся в position absolute или relative переписывать я это не хочу

179
Чем заменить родственный селектор css

Чем заменить родственный селектор css

В первом варианте без оберток табы отрабатывают за счет вот этих стилей:

191
Как удалить неиспользуемые стили css?

Как удалить неиспользуемые стили css?

В chrome нету вкладки "legacy audits"Для firefox расширения в новой версии уже не поддерживаются Те сервисы которые нагуглил - почти все не работают

193