In C++, hex ↔ string work splits cleanly into: parse hex characters into std::vector<std::byte> / std::string bytes, then interpret those bytes as text if needed. Modern C++ (17/20) keeps this readable without third-party libraries.
C-focused parsing: Convert hex in C. Tool: Hex to String.
Hex string → bytes (C++17)
#include <string>
#include <vector>
#include <stdexcept>
#include <cctype>
static int hex_val(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
throw std::invalid_argument("bad hex digit");
}
std::vector<unsigned char> hex_to_bytes(std::string_view hex) {
std::string clean;
clean.reserve(hex.size());
for (char c : hex) if (!std::isspace(static_cast<unsigned char>(c))) clean.push_back(c);
if (clean.size() % 2) throw std::invalid_argument("odd length");
std::vector<unsigned char> out;
out.reserve(clean.size() / 2);
for (size_t i = 0; i < clean.size(); i += 2) {
int v = (hex_val(clean[i]) << 4) | hex_val(clean[i + 1]);
out.push_back(static_cast<unsigned char>(v));
}
return out;
}
Bytes → text
#include <string>
std::string bytes_to_utf8_string(const std::vector<unsigned char>& bytes) {
return std::string(reinterpret_cast<const char*>(bytes.data()), bytes.size());
}
// usage
auto bytes = hex_to_bytes("e4bda0e5a5bd");
std::string text = bytes_to_utf8_string(bytes); // UTF-8 "你好" if console supports it
C++ std::string holds bytes; “UTF-8 string” is a convention, not a separate type. Validate UTF-8 if you accept untrusted input.
Bytes → hex
#include <sstream>
#include <iomanip>
std::string to_hex(const std::vector<unsigned char>& bytes) {
std::ostringstream oss;
oss << std::hex << std::setfill('0');
for (unsigned char b : bytes)
oss << std::setw(2) << static_cast<int>(b);
return oss.str();
}
C++20/23 projects can also use std::format for formatting; the parsing logic above stays the same.
Practical notes
- Reject odd length and non-hex digits — do not pad silently.
- Prefer
std::vector<unsigned char>(orstd::byte) for binary; usestd::stringwhen the payload is truly text. - For I/O-heavy code, avoid building giant intermediate strings when a streaming parser works.
Related: JavaScript · Java · hex overview.