2016-10-17 7 views
0

У меня есть дескриптор строки USB в массиве uint8_t. Например:Как напечатать дескриптор строки USB на cout/cerr в C++?

0000:12 03 34 00 45 00 36 00 31 00 42 00 43 00 30 00 ..4.E.6.1.B.C.0. 
0010:30 00           0. 

(Первые два байта длина и тип дескриптора, остальные байты являются uint16_t символов.)

Я хотел бы напечатать это на терминале как мало хлопот, насколько это возможно и, предпочтительно, без необходимости, чтобы ввернуть вокруг со всеми другими печати (что происходит, как cout << "Hello, world" << endl;)

в частности, я хотел бы сделать:

cout << "Serial number is: " << some_cast_or_constructor(buf + 2, len - 2) << endl; 

и для дескриптора строки выше, получим следующее в терминале:

Serial number is: 4E61BC00 

Возможно ли это, или мне придется копаться в тайнах Unicode?

[редактировать добавить:]

Per @PaulMcKenzie, я попробовал эту программу:

#include <iostream> 
#include <fstream> 
#include <exception> 
#include <string> 
#include <locale> 

int 
main(int argc, char **argv) 
{ 
    char buf[] = { 34, 00, 45, 00, 36, 00, 31, 00, 42, 00, 43, 00, 30, 00, 30, 00 }; 

    std::wcout << "Hello" << std::wstring((const wchar_t *)buf, sizeof(buf)) << std::endl; 

    return 0; 
} 

Выход:

user:/tmp$ g++ foo.cc 
user:/tmp$ ./a.out 
Hello?????????? 
user:/tmp$ 
+0

Используйте 'std :: wcout', а не' std :: cout'. – PaulMcKenzie

+0

Знаете ли вы, что такое 'uint16_t' байт? например, UTF-16? – Mine

+0

Я точно не знаю ... это код USB, который я написал, но дескрипторы определены как ассемблер '.string16" abcd "'. Hexdump - это именно то, что у меня есть в буфере памяти. Я пробовал std :: wcout (за @PaulMcKenzie), но я получаю кучу? Метки. –

ответ

1

В исходном коде, я обнаружить две ошибки: 1- в вашем USB rawdata (вверху), значения шестнадцатеричные и в ваших значениях buf [] являются десятичными. Оно должно быть написано:

char buf[] = { 0x34, 0x00, 0x45, 0x00, 0x36, 0x00, 0x31, 0x00, 0x42, 
         0x00, 0x43, 0x00, 0x30, 0x00, 0x30, 0x00 }; 

2- в сообщении печати, длина равна SizeOf (BUF), но это 'символ' (1 байт), а не 'wchar_t' (2bytes). Оно должно быть написано:

std::wcout << "Hello" << std::wstring((const wchar_t *)buf, (sizeof(buf) >> 1)) << std::endl; 

И этот код дает ожидаемый результат на ПК с Windows ... убедитесь, что нет большого/маленького преобразования обратного порядка байт перед тем управления «wchar_t» на вашем компьютере.

Не можете ли вы проверить размер (wchar_t) под Linux? Этот пост 'Difference and conversions between wchar_t for Linux and for Windows' предполагает, что wchar_t является 32-битным значением.

+0

Упс ... decimal вместо hex - глупая ошибка! Вырезать и вставить из hexdump не работает точно. Однако, даже с учетом ваших исправлений, он не работает на g ++/Linux (я также попытался преобразовать endianness, переместив 0 байт с конца массива в начало). Думаю, мне нужно больше узнать о многобайтовых символах и вводах-выводах. –

+0

Ха! Я только начал с этим заглядывать, и самое первое, что я сделал, это распечатать sizeof (wchar_t). Это 4, так что это моя первая проблема. USB использует UNICODE (каждый USB-2.0, раздел 9.6.7), но все, что я действительно знаю об этом, - это каждый пример, который я видел, использует .string16. Думаю, пришло время узнать, как работает UNICODE _really_! –

+0

(GCC/libstdC++ docs о преобразованиях символов) [https://gcc.gnu.org/onlinedocs/libstdc++/manual/facets.html#std.localization.facet.codecvt] –

0

Если вы достигли этого вопроса, потому что у вас возникли проблемы с Unicode, широкие символы и похожи на Linux, самый быстрый способ я нашел, чтобы двигаться вперед, чтобы использовать libiconv. Заголовочный файл <codecvt>, о котором вы будете читать в документах на C++, еще не реализован в GNU libstdC++ (по состоянию на октябрь 2016 года).

Вот краткий пример программы, которая демонстрирует libiconv:

#include <iostream> 
#include <locale> 
#include <cstdint> 
#include <iconv.h> 
#include <string.h> 

int 
main(int, char **) 
{ 
    const char  a[] = "ABC"; 
    const wchar_t b[] = L"ABC"; 
    const char  c[] = u8"ABC"; 
    const char16_t d[] = u"ABCDEF"; 
    const char32_t e[] = U"ABC"; 
    iconv_t   utf16_to_utf32 = iconv_open("UTF-32", "UTF-16"); 
    wchar_t   wcbuf[32]; 
    char   *inp = (char *)d; 
    size_t   inl = sizeof(d); 
    char   *outp = (char *)wcbuf; 
    size_t   outl = sizeof(wcbuf); 

    iconv(utf16_to_utf32, &inp, &inl, &outp, &outl); 

    std::wcout << "sizeof(a) = " << sizeof(a) << ' ' << a << std::endl 
       << "sizeof(b) = " << sizeof(b) << ' ' << b << std::endl 
       << "sizeof(c) = " << sizeof(c) << ' ' << c << std::endl 
       << "sizeof(d) = " << sizeof(d) << ' ' << d << std::endl 
       << "sizeof(e) = " << sizeof(e) << ' ' << e << std::endl 
       << "Converted char16_t to UTF-32: " << std::wstring(wcbuf, (wchar_t *)outp - wcbuf) << std::endl; 

    iconv_close(utf16_to_utf32); 

    return 0; 
} 

Результирующий выход:

[email protected]:~/code/unicode$ ./wchar 
sizeof(a) = 4 ABC 
sizeof(b) = 16 ABC 
sizeof(c) = 4 ABC 
sizeof(d) = 14 0x7ffefdae5a40 
sizeof(e) = 16 0x7ffefdae5a30 
Converted char16_t to UTF-32: ABCDEF 
[email protected]:~/code/unicode$ 

Обратите внимание, что STD :: wcout не печатает char16_t или char32_t правильно.Однако вы можете использовать iconv для преобразования UTF-16 (что, очевидно, вы получаете от u"STRING") до UTF-32 (который, по-видимому, совместим с wchar_t на поздней модели Linux-системы).