Std::cout不能正确打印由unsigned char数组的reinterpret_cast创建的Std::stri
std::cout not properly printing std::string created by reinterpret_cast of unsigned char array
我有一个存储1字节十六进制字符的unsigned char
数组,我想对这些值进行按位操作。
在使用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后对存储在字符串中的值进行位操作是否安全?我突然想到,所有这些可能都是毫无意义的,因为我相信我可以直接对无符号char进行二进制数学运算,不是吗?如能提供建议,不胜感激。
对于那些好奇的人,我正在尝试编写一个自定义的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::string
是字符串的表示形式,而不是纯粹的字节数组。因此,将它传递给std::cout
将显示一个字符串。您的printf
正在打印unsigned char
数组的单个值。与此等价的stl是std::vector<unsigned char>
。
您需要添加static_cast<unsigned>()
。否则,std::cout
将以char
ascii字符的形式打印每个unsigned char
值。输出将是R _ s h ~ ) 3 t t s r U
。您必须通过隐式地告诉它来防止这种转换。
谁能解释一下为什么std::cout会出现这种情况,而printf却不会?起初,我想也许我需要将其转换回unsigned char,但这样做没有效果。为什么转换为int给出正确的输出?
您告诉printf
以十六进制输出,因此它以十六进制输出。到底有什么神秘之处?
我要切换到Python,只是为了展示:
>>> s = [ 0x52, 0x5f, 0x73, 0x68, 0x7e, 0x29, 0x33, 0x74, 0x74, 0x73, 0x72, 0x55]
>>> ''.join(map(chr, s))
'R_sh~)3ttsrU'
我的意思是,这些是字节的ASCII等价物。这就是std::string
的构造函数所做的:取一个以空结尾的字符数组,并从那里构建一个字符串。你的reinterpret_cast
在unsigned 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
,它会自动提升为整数(但要小心!大多数类型不是,只有chars
和shorts
)。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 使用一个考虑到std::map中键值的滚动或换行的键
- 如何从 std::atomic 中提取指针 T<T>?
- 为什么 std::unique 不调用 std::sort?
- 使用std::函数映射对象方法
- 可组合的lambda/std::函数与std::可选