C++ std::cout无法正确打印通过重新解释无符号字符数组的强制转换创建的std::字符串

C++ std::cout无法正确打印通过重新解释无符号字符数组的强制转换创建的std::字符串,c++,cout,stdstring,reinterpret-cast,C++,Cout,Stdstring,Reinterpret Cast,我有一个无符号字符数组,它存储1字节十六进制字符,我想对这些值进行位运算 在使用reinterpret_cast将它们转换为字符串(使用std::stringstream和std::bitset执行必要的操作)之后,我尝试打印字符串以查看内容。相当奇怪的是,我注意到std::cout没有给出预期的结果,但是使用printf却得到了 下面是一个简单的例子: int main(int argc, char *argv[]) { unsigned char my_txt[] = {

我有一个
无符号字符
数组,它存储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;
}
我下定决心要找到一个解决办法,于是在周围修补了一段时间——我猜测,重新解释演员阵容可能是导致这种行为的原因。我最终发现这样做:

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

std::cout我正在切换到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结尾的字符数组,并从中构建一个字符串。您的
重新解释\u cast
无符号字符*
字符*
之间进行强制转换,这是为数不多的安全操作之一

您可能想要的是用整数的文本表示构建一个字符串。对于该用途
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;
std::ostringstream操作系统;
os改变

std::cout << my_std_string << std::endl;    // Bad stuff happens :S
std::cout
有人能解释为什么std::cout而不是printf会发生这种情况吗?起初,我认为可能需要将其转换回unsigned char,但这样做没有效果。为什么强制转换为int会给出正确的输出


您让printf
以十六进制输出,所以它以十六进制输出。到底是什么秘密?

你想要的是什么?根据ascii表,这似乎是正确的。您不存储“1字节十六进制字符”。存储字节。您在文本中编写的用于将这些值输入到程序源代码中的数字的基数是不相关的。此外,您的
printf
std::cout
方法甚至不尽相同,因此抱怨它们的结果不同似乎对所讨论的编程语言有点不公平。您混淆了表示和值。您可能希望看到与此问题相关的这些。简而言之,
52 5F 73 68 7E 29 33 74 74 72 55
R_sh~)3ttsrU
都是
{0x52,0x5f,0x73,0x68,0x7e,0x29,0x33,0x74,0x74,0x73,0x72,0x55}的有效表示字节序列。谢谢@LightnessRacesinOrbit和milleniumbug。是的,看来我对基本知识有点生疏了哈哈,所以我假设它是安全的,然后,对存储在字符串中的值进行二进制计算(位屏蔽,将字节相加,等等)?@KnightsValour:当然为什么不?正确-我认为在cout语句中添加std::hex会达到同样的效果。正如@tillaert所指出的,字符串并不是字节数组,我似乎期待它是字节数组。谢谢你的澄清!谢谢你的解释,@tilart!你能解释一下为什么它需要转换为int(而不是无符号类型)吗?看起来静态的_转换为非此即彼产生了相同的答案。好吧,只要这个值可以安全操作,我想我没事。再次感谢!感谢您的详细解释和代码!我想输出对我来说并不是绝对必要的——因为我只需要确保值被正确地放入带有reinterpret_cast的字符串中。只要我能对这些值进行二进制计算,然后存储它们——我想我会没事的。但是,我会把你的代码放在手边作为参考。@KnightsValour:没问题。但是如果你想存储<代码>无符号字符< /代码>,请考虑使用<代码> STD::vector < /代码>。代码>标准::字符串
用于文本,而不是原始字节,它迟早会给您带来麻烦。谢谢您的建议。为了澄清,我使用的是一个供应商的库,它提供结构作为消息帧的容器。在此结构中,数据字节存储在具有以下声明的数组中:uint8_t data[8]。考虑到这一点,我需要能够对字节进行二进制计算,其他文章也提到了使用std::stringstream和std::bitset。这就是我最初想到使用std::string作为容器的原因——最终,这些信息将使用协议缓冲区序列化。是否有更好的方法满足我的要求?
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;