如何在c++中在cout/cerr上打印USB字符串描述符

How to print a USB string descriptor on cout/cerr in c++?

本文关键字:打印 USB 字符串 描述 cerr c++ 中在 cout      更新时间:2023-10-16

我在uint8_t数组中有一个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的奥秘?

[edit to add:]

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$ 

在你的源代码中,我检测到两个错误:1-在你的USB原始数据(在顶部),值是十六进制,在你的buf[]值是十进制。应该这样写:

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

2-在打印消息中,长度等于sizeof(但是),但它是'char'(1字节)而不是'wchar_t'(2字节)。应该这样写:

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

并且,这段代码给出了Windows PC上的预期结果…在您的计算机上管理'wchar_t'之前,请确保没有大/小端序转换。

你能检查一下Linux下的size (wchar_t)吗?这篇文章Linux和for的wchar_t的区别和转换Windows假定wchar_t是一个32位的值。

如果您遇到这个问题是因为您在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;
}

输出结果:

user@debian:~/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
user@debian:~/code/unicode$ 

注意std::wcout不能正确打印char16_t或char32_t。但是,您可以使用iconv将UTF-16(这显然是您从u"STRING"获得的)转换为UTF-32(这显然与最新型号的Linux系统上的wchar_t兼容)。