Skip to main content

Memory Read & Write

STX provides four fundamental functions for typed memory access: copy-based operations using std::memcpy for well-defined behavior, and raw pointer operations for performance-critical scenarios.

Copy-Based Read

read()

Safely reads a value from memory using std::memcpy, providing well-defined behavior under the C++ object model.
template<class Type, address_like Addr>
[[nodiscard]] Type read(Addr base, offset_t off = offset_t{0}) noexcept;
Type
template parameter
required
The type to read. Must satisfy std::is_trivially_copyable_v<Type>.
Addr
template parameter
required
Address-like type (satisfies address_like concept). Can be raw pointers, va_t, rva_t, or other address types.
base
Addr
required
Base address to read from.
off
offset_t
default:"offset_t{0}"
Offset from base address in bytes.
Returns: Value of type Type read from base + off.

Characteristics

  • Uses std::memcpy for defined behavior
  • Safe for unaligned memory access
  • Compliant with strict aliasing rules
  • Zero runtime overhead when inlined
  • Requires trivially copyable types

When to Use

ScenarioRecommended
Parsing binary structures✓ Yes
Packed/unaligned memory✓ Yes
Portable code✓ Yes
Memory-mapped files✓ Yes
Known-aligned buffersConsider read_raw()

Example

#include <lbyte/stx.hpp>

using namespace lbyte::stx;

struct Header {
    u32 magic;
    u16 version;
    u16 flags;
};

va_t base{0x140000000};

// Read structure from memory
Header h = read<Header>(base, offset_t{0x100});

// Read primitive type
u32 value = read<u32>(base, offset_t{0x200});

// Works with unaligned addresses
u64 unaligned = read<u64>(reinterpret_cast<void*>(0x1001), offset_t{3});

Raw Pointer Read

read_raw()

Directly dereferences a pointer for maximum performance. Requires proper alignment and careful usage.
template<class Type>
[[nodiscard]] Type read_raw(address_like auto base,
                            offset_t off = offset_t{0}) noexcept;
Type
template parameter
required
The type to read. Must satisfy std::is_trivially_copyable_v<Type>.
base
address_like auto
required
Base address to read from.
off
offset_t
default:"offset_t{0}"
Offset from base address in bytes.
Returns: Value of type Type read from base + off via direct dereference.

Characteristics

  • Direct pointer dereference (no memcpy)
  • Requires properly aligned memory
  • May violate strict aliasing if misused
  • Maximum performance in tight loops
  • Requires trivially copyable types
Alignment Required: Using read_raw() with misaligned addresses causes undefined behavior on most architectures. Use read() for unaligned access.

When to Use

ScenarioRecommended
Known-aligned internal buffers✓ Yes
Performance-critical tight loops✓ Yes
Memory-mapped files✗ No
Arbitrary external memory✗ No

Example

#include <lbyte/stx.hpp>

using namespace lbyte::stx;

// Aligned buffer
alignof(u64) u64 buffer[1024];

// Safe: buffer is properly aligned
u64 value = read_raw<u64>(buffer, offset_t{64});

// Performance-critical loop
for (usize i = 0; i < 1000; ++i) {
    u32 val = read_raw<u32>(buffer, offset_t{i * sizeof(u32)});
    // process val...
}

Copy-Based Write

write()

Safely writes a value to memory using std::memcpy, providing well-defined behavior.
template<class Type, address_like Addr>
void write(Addr base, offset_t off, Type value) noexcept;
Type
template parameter
required
The type to write. Must satisfy std::is_trivially_copyable_v<Type>.
Addr
template parameter
required
Address-like type (satisfies address_like concept).
base
Addr
required
Base address to write to.
off
offset_t
required
Offset from base address in bytes.
value
Type
required
Value to write to memory.

Characteristics

  • Uses std::memcpy for defined behavior
  • Safe for unaligned memory access
  • Portable across platforms
  • Zero runtime overhead when inlined
  • Requires trivially copyable types

Example

#include <lbyte/stx.hpp>

using namespace lbyte::stx;

va_t base{0x140000000};

// Write primitive value
write<u32>(base, offset_t{0x300}, 0xDEADBEEF);

// Write structure
struct Config {
    u32 flags;
    u32 timeout;
};

Config cfg{0x01, 5000};
write<Config>(base, offset_t{0x400}, cfg);

// Safe for unaligned addresses
write<u64>(reinterpret_cast<void*>(0x1001), offset_t{3}, 0x123456789ABCDEF0);

Raw Pointer Write

write_raw()

Directly writes through a pointer for maximum performance. Requires proper alignment.
template<class Type>
void write_raw(address_like auto base,
               offset_t off,
               Type value) noexcept;
Type
template parameter
required
The type to write. Must satisfy std::is_trivially_copyable_v<Type>.
base
address_like auto
required
Base address to write to.
off
offset_t
required
Offset from base address in bytes.
value
Type
required
Value to write to memory.

Characteristics

  • Direct assignment through cast pointer
  • Requires properly aligned memory
  • No aliasing guarantees
  • Maximum performance in controlled regions
  • Requires trivially copyable types
Alignment Required: Using write_raw() with misaligned addresses causes undefined behavior. Use write() for unaligned access.

Example

#include <lbyte/stx.hpp>

using namespace lbyte::stx;

// Aligned buffer
alignof(u64) u64 buffer[1024];

// Safe: buffer is properly aligned
write_raw<u64>(buffer, offset_t{64}, 0xCAFEBABE);

// Performance-critical loop
for (usize i = 0; i < 1000; ++i) {
    write_raw<u32>(buffer, offset_t{i * sizeof(u32)}, i);
}

Comparison: Copy vs. Raw

Featureread() / write()read_raw() / write_raw()
Implementationstd::memcpyDirect dereference
Alignment requirementNoneMust be aligned
Strict aliasingSafePotential issues
Unaligned access✓ Safe✗ Undefined behavior
PerformanceExcellent (optimized away)Maximum
PortabilityHighMedium
Use caseGeneral purposePerformance-critical

Safety Considerations

Memory Validity: All functions assume the caller ensures:
  • Memory region is valid and accessible
  • No concurrent access or race conditions
  • Proper lifetime management
  • No bounds checking is performed
ResponsibilityOwner
Memory validityCaller
Alignment correctnessCaller (raw operations)
Concurrency safetyCaller
Bounds checkingCaller

Performance Notes

  • Modern compilers optimize std::memcpy to single instructions for aligned access
  • The STX_FORCE_INLINE attribute ensures zero abstraction overhead
  • For small, known-aligned types, read() and read_raw() generate identical code
  • Use raw operations only when profiling shows measurable benefit

Integration with Strong Types

All functions work seamlessly with STX strong types:
#include <lbyte/stx.hpp>

using namespace lbyte::stx;

// Using va_t (virtual address)
va_t virtual_addr{0x140000000};
u32 val1 = read<u32>(virtual_addr, offset_t{0x100});

// Using rva_t (relative virtual address)
rva_t relative_addr{0x1000};
u64 val2 = read<u64>(relative_addr, offset_t{0x50});

// Using raw pointers
void* raw_ptr = get_memory_region();
write<u32>(raw_ptr, offset_t{0}, 0x12345678);

Casting Utilities

STX provides three inline casting utilities for common type conversions in low-level code.

rcast()

Wrapper for reinterpret_cast with shorter syntax.
template<class Type>
Type rcast(auto value) noexcept;
Type
template parameter
required
Target type to cast to.
value
auto
Value to cast.
Example:
void* ptr = get_buffer();
u8* byte_ptr = rcast<u8*>(ptr);

uptr address = rcast<uptr>(ptr);
Use rcast with caution. Improper use of reinterpret_cast can lead to undefined behavior. Ensure proper alignment and type compatibility.

scast()

Wrapper for static_cast with shorter syntax and constexpr support.
template<class Type>
constexpr Type scast(auto value) noexcept;
Type
template parameter
required
Target type to cast to.
value
auto
Value to cast.
Example:
u64 large = 0x123456789;
u32 small = scast<u32>(large);  // Narrowing conversion

double d = 3.14;
int i = scast<int>(d);  // Floating to integer

bcast()

Wrapper for std::bit_cast with shorter syntax and constexpr support.
template<typename To, typename From>
[[nodiscard]] constexpr To bcast(const From& from) noexcept;
To
template parameter
required
Target type. Must be same size as From and both must be trivially copyable.
From
template parameter
required
Source type.
from
const From&
Value to bit-cast.
Example:
// Reinterpret float bits as integer
f32 pi = 3.14159f;
u32 bits = bcast<u32>(pi);

// Type-punning between compatible types
struct Vec2 { f32 x, y; };
struct Point { f32 coords[2]; };

Vec2 vec{1.0f, 2.0f};
Point pt = bcast<Point>(vec);
bcast provides safe type-punning with compile-time size checks, making it the preferred alternative to union-based or pointer-based type reinterpretation.

Design Notes

  • All casting utilities are marked STX_FORCE_INLINE for zero overhead
  • scast and bcast are constexpr, enabling compile-time conversions
  • These utilities maintain the same semantics as their standard library counterparts while providing shorter syntax for low-level code

Build docs developers (and LLMs) love