繁体   English   中英

std :: cout无法正确打印由无符号字符数组的reinterpret_cast创建的std :: string

[英]std::cout not properly printing std::string created by reinterpret_cast of unsigned char array

我有一个unsigned char数组,存储1个字节的十六进制字符,我想对这些值进行按位运算。

在使用reinterpret_cast将它们放入字符串之后(使用std :: stringstream和std :: bitset进行必要的操作),我尝试打印该字符串以查看内容。 奇怪的是,我注意到std :: cout没有给出预期的结果,但是使用printf却给出了预期的结果!

这是一个简单的示例:

int main(int argc, char *argv[])
{

    unsigned char my_txt[] = {
        0x52, 0x5f, 0x73, 0x68, 0x7e, 0x29, 0x33, 0x74, 0x74, 0x73, 0x72, 0x55
    };
    unsigned int my_txt_len = 12;

    std::string my_std_string(reinterpret_cast<const char *>(my_txt), my_txt_len);

    for (size_t i=0;i<my_txt_len;i++)
        printf("%02X ", my_std_string[i]);      // Works fine!
    printf("\n");

    std::cout << my_std_string << std::endl;    // Bad stuff happens :S

    return 0;
}

输出:

52 5F 73 68 7E 29 33 74 74 73 72 55     // Expected
R_sh~)3ttsrU                            // ??

下定决心要找到解决方案,我纠结了一段时间-猜测reinterpret_cast可能会导致这种行为。 我最终发现这样做:

std::cout << std::hex << (int)my_std_string[0] << std::dec << std::endl;

至少对于第一个角色还是产生了预期的结果。 循环遍历也为其他11个字节提供了正确的值。

有人可以解释为什么使用std :: cout而不是printf会发生这种情况吗? 起初,我以为我可能需要将其强制转换回unsigned char但是这样做没有任何效果。 为什么强制转换为int给出正确的输出?

在像我以前使用reinterpret_cast之后,对存储在字符串中的值进行按位运算安全吗? 在我看来,所有这些可能都毫无意义,因为我相信我可以直接在无符号字符上进行二进制数学运算,不是吗? 这里的建议将不胜感激。

对于那些好奇的人,我尝试编写一个自定义C ++控制台应用程序(Windows 7 64位计算机上的Microsoft Visual Studio 2010),以使用供应商的API与CAN-USB适配器接口。 我希望接收(作为较大的“接收框架”结构的一部分)带有十六进制值的8字节无符号字符数组,我需要处理这些值以获取适用于我的应用程序的数据。 然后将处理后的数据存储在协议缓冲区中,以便在matlab中进行进一步解释。

抱歉,这似乎是一个愚蠢的问题-我来自硬件背景,而且一段时间以来没有做任何认真的编程(有关SO的第一篇文章!)。

更改

std::cout << my_std_string << std::endl;    // Bad stuff happens :S

for( std::size_t i = 0; i < my_txt_len ; i++ )
{
    std::cout << std::hex << static_cast<unsigned>(my_std_string[i]) << " " ;
}
std::cout << std::endl;

std::stringstd::string的表示,而不仅仅是字节数组。 因此,将其传递给std::cout将显示一个字符串。 您的printf正在打印unsigned char数组的各个值。 相当于stl的是std::vector<unsigned char>

您需要添加static_cast<unsigned>() 否则, std::cout将把每个unsigned char值打印为char ascii字符。 输出将为R _ sh ~ ) 3 ttsr U 您必须通过隐式告诉它来防止这种转换。

我切换到Python,只是为了展示一下:

>>> s = [ 0x52, 0x5f, 0x73, 0x68, 0x7e, 0x29, 0x33, 0x74, 0x74, 0x73, 0x72, 0x55]
>>> ''.join(map(chr, s))
'R_sh~)3ttsrU'

我的意思是,这些是您字节的ASCII等效项。 这就是std::string的构造函数的作用:取一个以nul结尾的字符数组,然后从那里构建一个字符串。 您的reinterpret_castunsigned char*char*之间进行强制转换,这是它执行的少数安全操作之一。

您可能想要的是用整数的文本表示形式构建一个字符串。 为此,请使用std::ostringstream

std::ostringstream os;
os << std::hex << std::setfill('0') << std::uppercase;
for (size_t i=0;i<my_txt_len;i++)
    os << std::setw(2) << my_txt[i] << " ";
std::string txt = os.str();

std::cout << txt;

使用printf时不会出现此问题,因为printf参数的类型是由格式字符串设置的,在您的情况下, %X表示读取为整数,而写入为十六进制。 如果您传递一个char/unsigned char它会自动提升为整数(但要注意!大多数类型都不以这种方式提升,只有charsshorts )。

有人可以解释为什么使用std :: cout而不是printf会发生这种情况吗? 起初,我以为我可能需要将其强制转换回未签名的char,但是这样做没有任何效果。 为什么强制转换为int给出正确的输出?

您告诉printf以十六进制输出,因此以十六进制输出。 到底有什么奥秘?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM