2016-10-17 72 views
0

我有一個uint8_t數組中的USB字符串描述符。例如:如何在cout/cerr上打印USB字符串描述符?

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的奧祕?

[編輯補充:]

每@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(per @PaulMcKenzie),但我得到了一堆?分數。 –

回答

1

在源代碼中,我發現了兩個錯誤: 1-在您的USB原始數據中(頂部),值爲十六進制,並且在您的buf []值爲十進制。應該寫成:

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

在打印消息2-,該lenght是等於sizeof(BUF),但它是 '字符'(1個字節),而不是 'wchar_t的'(2字節)。應該寫成:

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

而且,這個代碼給出了在Windows PC上預期的結果......肯定沒有管理計算機上的「wchar_t的」前的大/小尾數轉換。

你可以在Linux下檢查sizeof(wchar_t)嗎?這篇文章 'Difference and conversions between wchar_t for Linux and for Windows'假設wchar_t是一個32位的值。

+0

哎呀...十進制而不是十六進制是一個愚蠢的錯誤!從hexdump剪切和粘貼不能正確運行。 然而,即使你的更正,它不適用於g ++/Linux(我也嘗試通過將0字節從數組末尾移動到開頭來交換字節序)。 我想我將不得不更多地瞭解多字節字符和I/O。 –

+0

哈!我剛開始討論這個,我做的第一件事是打印出sizeof(wchar_t)。這是4,所以這是我的第一個問題。 USB使用UNICODE(每個USB-2.0秒9.6.7),但我真正瞭解它的是我見過的每個使用.string16的例子。我想是時候瞭解UNICODE _really_是如何工作的! –

+0

(關於字符集轉換的GCC/libstdC++文檔)[https://gcc.gnu.org/onlinedocs/libstdc++/manual/facets.html#std.localization.facet.codecvt] –

0

如果您因爲在Linux上遇到Unicode,寬字符和類似問題而遇到此問題,我發現最快的方法是使用libiconv。您將在C++文檔中閱讀的<codecvt>頭文件尚未在GNU libstdC++中實現(截至2016年10月)。

下面是一個說明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$ 

注意,標準:: wcout不打印char16_t和char32_t正常。但是,您可以使用iconv將UTF-16(顯然是您從u"STRING"獲得的內容)轉換爲UTF-32(顯然,它與新型Linux系統上的wchar_t兼容)。