I (C++ newbie) am currently trying to implement the following function:
std::string bytes_to_hex(const std::string &bytes);
The function should basically return a base16 encoding of a given byte array:
std::string input{0xde, 0xad, 0xbe, 0xef} => "deadbeef"
My first version doesn't quite work how I imagined:
std::string bytes_to_hex(const std::string &bytes) {
std::ostringstream ss;
ss << std::hex;
for (auto &c : bytes) {
ss << std::setfill('0') << std::setw(2) << +c;
}
return ss.str();
}
With this function the output is:
ffffffdeffffffadffffffbeffffffef
After some experiments, I've found out that this version looks better:
std::string bytes_to_hex(const std::string &bytes) {
std::ostringstream ss;
ss << std::hex;
for (const char &c : bytes) {
ss << std::setfill('0') << std::setw(2) << +(static_cast<uint8_t>(c));
}
return ss.str();
}
The output is as expected:
deadbeef
My question is:
- Why does the second version work and the first doesn't? What is the main difference here?
- Is the second version correct implementation of my original intention or can there be other problems?
+does nothing, casting however did what you wanted, ie made sure the bytes are interpreted as positive numberschartype can be eithersignedorunsigned, it's up tot he compiler. In your case they seem to besigned, which means when the characters are promoted tointthey are also sign extended.+forces integer promotion of the character.std::stringcan be used for arbitrary data, it does have its drawbacks. One of them you just discovered. That's why I always recommendstd::vector<uint8_t>for arbitrary byte data.