我编写了多个简单的 C++ 函数来将字节序列转换为字符串表示形式。
这非常简单,我确信我的逻辑是正确的,我认为这非常简单,直到我开始打印字符串,我发现输出是垃圾:
#include <iostream>
#include <string>
#include <vector>
using std::vector;
typedef vector<uint8_t> bytes;
using std::string;
using std::cout;
using namespace std::literals;
string DIGITS = "0123456789abcdef"s;
static inline string hexlify(bytes arr) {
string repr = ""s;
for (auto& chr : arr) {
repr += " " + DIGITS[(chr & 240) >> 4] + DIGITS[chr & 15];
}
repr.erase(0, 1);
return repr;
}
bytes text = {
84, 111, 32, 98, 101, 32,
111, 114, 32, 110, 111, 116,
32, 116, 111, 32, 98, 101
}; // To be or not to be
int main() {
cout << hexlify(text);
}
2♠
÷82♠
÷82♠
÷82♠
÷
为什么会出现这种情况?
我知道我的逻辑是对的,以下是Python的直接翻译:
digits = "0123456789abcdef"
def bytes_string(data):
s = ""
for i in data:
s += " " + digits[(i & 240) >> 4] + digits[i & 15]
return s[1:]
它有效:
>>> bytes_string(b"To be or not to be")
'54 6f 20 62 65 20 6f 72 20 6e 6f 74 20 74 6f 20 62 65'
但是为什么它在 C++ 中不起作用?
我使用的是 Visual Studio 2022 V17.9.7,编译器标志:
/permissive- /ifcOutput "hexlify_test\x64\Release\" /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"hexlify_test\x64\Release\vc143.pdb" /Zc:inline /fp:precise /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /std:c17 /Gd /Oi /MD /std:c++20 /FC /Fa"hexlify_test\x64\Release\" /EHsc /nologo /Fo"hexlify_test\x64\Release\" /Ot /Fp"hexlify_test\x64\Release\hexlify_test.pch" /diagnostics:column
正如评论中所指出的(也这里),这里的问题在于字符串连接或周围。以下代码不进行串联:
" " + DIGITS[(chr & 240) >> 4]
当您从字符串
DIGTS
中提取字符时,它具有类型 char
— 单个字符的专用类型。由于历史原因(与 C 兼容),+
运算符将字符串文字 " "
解释为指针,将数字字符解释为整数,并执行一些无用的指针运算。
要进行串联,请使用
std::string
类型的字符串文字,就像您在代码中其他地方所做的那样:
" "s + DIGITS[(chr & 240) >> 4]
在这里,
operator+
遇到了正确的类型std::string
和char
,所以它可以正常工作。