2013-07-29 5 views
2

Я получаю 16 бит от структуры в памяти, и мне нужно преобразовать их в строку. 16 бит представляют собой Юникод символ:Преобразование 16 бит в память в std :: string

typedef struct my_struct { 
    unsigned unicode  : 16; 
} my_struct; 

я начал литье бит в неподписанный символ, который работал для значений достаточно малы, чтобы поместиться в один символе. Однако для таких символов, как «♪», он усекает неправильно. Это то, что я до сих пор:

 char buffer[2] = { 0 }; 
     wchar_t wc[1] = { 0 }; 

     wc[0] = page->text[index].unicode; 
     std::cout << wc[0] << std::endl; //PRINT LINE 1 
     int ret = wcstombs(buffer, wc, sizeof(buffer)); 
     if(ret < 0) 
      printf("SOMETHING WENT WRONG \n"); 
     std::string my_string(buffer); 
     printf("%s \n", my_string.c_str()); //PRINT LINE 2 

печать линия 1 в настоящее время печатает: «9834» и печать линии 2 печатает: «» (пустая строка). Я пытаюсь заставить my_string содержать '♪'.

+3

Вы не можете поместить 16 бит в 8 бит, не теряя что-то. Ваш выбор состоит в том, чтобы преобразовать (по-видимому) UTF-16 в UTF-8 (использует несколько 8-битных символов для хранения одного 16-битного кода) или оставить его в UTF-16 (например, 'std :: wstring' содержит единицы измерения of 'wchar_t', который * может * быть UTF-16). Если ни один из них не работает, вы можете создать экземпляр 'std :: basic_string' над вашим' my_struct' напрямую: 'std :: basic_string что угодно;' –

+1

Вы не можете положить 16 фунтов муки в 8-фунтовый мешок. –

+0

Вы не можете поместить 16 бит в 8-бит 'char'. Почему, по-вашему, вам нужно? Возможно, просто поместите его в 'wchar_t' (или' std :: wstring'). – zindorsky

ответ

2

Если я сделал мое преобразование правильно, 0x9834 в UTF-16 (16 бит Unicode) переводится в три байта последовательность 0xE9, 0xA0, 0xB4 в UTF-8 (8-разрядный Unicode). Я не знаю о других узких кодировках байтов , но я сомневаюсь, что они были бы короче 2 байтов. Вы передаете буфер из двух байтов в wcstombs, что означает возвращенную строку длиной не более 1 байта. wcstombs останавливается перевод (без сбоев!), Когда больше нет места в буфере назначения . Вы также не смогли L'\0' завершить входной буфер . Это не проблема на данный момент, потому что wcstombs прекратит перевод, прежде чем он туда доберется, но вы, , обычно должны добавить дополнительные L'\0'.

Так что делать:

Во-первых, и передовое, при отладке такого рода вещи, посмотрите на возвращаемое значение wcstombs. Готов поспорить, что это 0, потому что нехватки места.

Во-вторых, я бы дал себе немного разницы. Юридический Юникод может содержать до 4 байтов в UTF-8, поэтому я бы выделил в наименее 5 байтов для вывода (не забудьте трейлинг '\0'). Вдоль тех же линий вам нужен задний конец L'\0' для ввода. Итак:

char buffer[ 5 ]; 
wchar_t wc[] = { page->text[index].unicode, L'\0' }; 
int ret = wcstombs(buffer, wc, sizeof(buffer)); 
if (ret < 1) { // And *not* 0 
    std::cerr << "OOPS\n"; 
} 
std::string str(buffer, buffer + ret); 
std::cout << str << '\n'; 

Конечно, после всего этого, есть еще вопрос о том, что (конечный) дисплей делает с UTF-8 (или любого другой многобайтового кодированием узкого характера is-- -UTF-8 почти универсальный под Unix, но я не уверен в Windows.) Но , так как вы говорите, что отображение "\u9834", похоже, работает, оно должно быть в порядке.

+0

Консоль Windows может отображать UTf-8 _in theory_, но получить ее на самом деле это сложно. –

+0

Я знаю, что вы не можете вглядываться в мои компьютер, но с этим кодом wcstombs возвращает -1, когда появляется символ со значением> 127. ** edit: ** err not char, но вы знаете, что я имею в виду – mirandak

+0

Думаю, что это была проблема локали, потому что я ударил «setlocale (LC_ALL,« »),« там, и это внезапно сработало! Теперь, чтобы выяснить, какой язык мне действительно нужен ... Но спасибо !!! – mirandak

1

Пожалуйста, прочитайте немного о том, что значит «кодировка символов», как это: What is character encoding and why should I bother with it

Затем выяснить, какую кодировку вы получаете в, и какую кодировку вы должны использовать на выходе. Это означает выяснить, что ожидает ваш формат файла/библиотека/консоль GUI.

Затем используйте что-то надежное, как libiconv, чтобы конвертировать между ними, а не так называемые wcstombs() + wchar_t.

Например, вы можете обнаружить, что ваш вход UCS-2, и вам нужно вывести его в UTF-8. Моя система имеет 32-битный wchar_t, я бы не рассчитывал на то, что он будет конвертировать из UCS-2 в UTF-8.

1

Для преобразования из UTF-16 в UTF-8, используйте codecvt_utf8<char16_t>:

#include <iostream> 
#include <string> 
#include <locale> 
#include <codecvt> 

int main() { 
    char16_t wstr16[2] = {0x266A, 0}; 
    auto conv = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}; 
    auto u8str = std::string{conv.to_bytes(wstr16)}; 
    std::cout << u8str << '\n'; 
} 
+0

В чем смысл 'auto u8str = std :: string {conv.to_bytes (wstr16)};', а не 'std :: string u8str (conv.to_bytes (wstr16));', кроме, может быть, обфускации? –

+0

моя кодовая база не в C++ 11 :( – mirandak

+0

@JamesKanze это стиль AAA: http://herbsutter.com/2013/06/13/gotw-94-special-edition-aaa-style-almost-always-auto/ – ecatmur