1. Problem It Solves
Safe binary parsing must bound every read, represent raw bytes explicitly, copy object representation legally, and normalize external byte order. It makes an important assumption visible and checkable.
2. Prerequisites
Spans, byte representation, bit operations, and endian from Days 28 and 36.
You should be able to compile a short program and read its output.
3. Core Idea
A span is the packet boundary, std::byte says “raw data,” bit_cast reconstructs a same-sized representation, and endian logic translates wire order. Read std::span<const std::byte> as a precise promise; runtime preconditions still belong to the programmer.
4. Minimal Syntax
std::span<const std::byte> packet{raw};
auto value = std::bit_cast<std::uint32_t>(field);5. How It Works
The program introduces the smallest relevant form of
std::span<const std::byte>.It applies the feature to fixed data while required owners remain in scope.
It prints one result that can be checked against the source.
6. Common Mistakes
Reading past the span is invalid, casting an unaligned byte pointer to an integer pointer can violate alignment and aliasing, and native endian is not wire endian.
Also check the required header, C++20 library support, lifetime, and deduced types.
7. When to Use It
Use it when a fixed binary field has a documented width and byte order.
Avoid it when the format is textual, variable-length without validation, or requires richer schema handling.
8. Simple Example
Four fixed little-endian bytes are copied into an array, bit-cast to uint32_t, and normalized on big-endian hosts. The companion .cpp uses no input, so its result is easy to reproduce.
Complete sample code
Source file
cpp20/52_binary_parsing_span_byte_bit_cast_endian/main.cpp
// Day 52: Binary Parsing with span, byte, bit_cast, and Endian
#include <array>
#include <bit>
#include <cstddef>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <span>
constexpr std::uint32_t swap32(std::uint32_t value) {
return ((value & 0x000000FFu) << 24)
| ((value & 0x0000FF00u) << 8)
| ((value & 0x00FF0000u) >> 8)
| ((value & 0xFF000000u) >> 24);
}
int main() {
std::array raw{
std::byte{0x78}, std::byte{0x56},
std::byte{0x34}, std::byte{0x12}};
std::span<const std::byte> packet{raw};
std::array<std::byte, 4> field{};
for (std::size_t i = 0; i < field.size(); ++i) field[i] = packet[i];
std::uint32_t value = std::bit_cast<std::uint32_t>(field);
if constexpr (std::endian::native == std::endian::big) {
value = swap32(value);
} else if constexpr (std::endian::native != std::endian::little) {
value = std::to_integer<std::uint32_t>(field[0])
| (std::to_integer<std::uint32_t>(field[1]) << 8)
| (std::to_integer<std::uint32_t>(field[2]) << 16)
| (std::to_integer<std::uint32_t>(field[3]) << 24);
}
std::cout << "value = 0x" << std::hex << value << '\n';
}
9. Key Takeaways
std::span<const std::byte>expresses the central C++20 idea of this day.The example isolates one behavior with fixed data.
Compiler checks do not replace lifetime and runtime reasoning.
Prefer the smallest interface that states the real requirement.
10. Self-Check Questions
Easy — What is the main job of
std::span<const std::byte>in the minimal example?Medium — What hexadecimal value is parsed from bytes
78 56 34 12in little-endian order?Hard — Why is copying into
std::array<std::byte,4>and then bit-casting safer than dereferencing areinterpret_cast<uint32_t*>into the packet?