Overview
The STX library provides a comprehensive set of type aliases that offer fixed-width integers, floating-point types, and platform-consistent size and pointer types. These aliases improve code clarity, ensure ABI stability, and provide a consistent interface across platforms.
All types are defined in the lbyte::stx namespace and are header-only, constexpr-friendly, and have zero runtime overhead.
Unsigned Integer Types
Fixed-width unsigned integer types for precise memory layout control.
8-bit unsigned integer type.
Example:
stx::u8 byte = 0xFF;
stx::u8 flag = 1;
u16
using u16 = std::uint16_t;
16-bit unsigned integer type.
Example:
stx::u16 port = 8080;
stx::u16 count = 1024;
u32
using u32 = std::uint32_t;
32-bit unsigned integer type.
Example:
stx::u32 magic = 0x464C457F; // ELF magic number
stx::u32 size = 1048576; // 1 MB
u64
using u64 = std::uint64_t;
64-bit unsigned integer type.
0 to 18,446,744,073,709,551,615
Example:
stx::u64 file_size = 1ULL << 40; // 1 TB
stx::u64 timestamp = 1234567890123;
Signed Integer Types
Fixed-width signed integer types for arithmetic operations requiring negative values.
8-bit signed integer type.
Example:
stx::i8 delta = -5;
stx::i8 temperature = -40;
i16
using i16 = std::int16_t;
16-bit signed integer type.
Example:
stx::i16 offset = -100;
stx::i16 elevation = 2500;
i32
using i32 = std::int32_t;
32-bit signed integer type.
-2,147,483,648 to 2,147,483,647
Example:
stx::i32 coordinate = -50000;
stx::i32 difference = -1024;
i64
using i64 = std::int64_t;
64-bit signed integer type.
-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
Example:
stx::i64 large_offset = -1000000000LL;
stx::i64 time_diff = -3600000000;
Floating-Point Types
Aliases for IEEE 754 floating-point types.
f32
Single-precision (32-bit) floating-point type.
Example:
stx::f32 ratio = 0.75f;
stx::f32 pi = 3.14159f;
f64
Double-precision (64-bit) floating-point type.
Example:
stx::f64 precise_pi = 3.141592653589793;
stx::f64 large_value = 1e308;
Size and Difference Types
Platform-consistent types for sizes, offsets, and pointer arithmetic.
usize
using usize = std::size_t;
Unsigned size type, represents the size of any object in bytes. Platform-dependent (32-bit on 32-bit platforms, 64-bit on 64-bit platforms).
Array sizes, memory allocation sizes, container sizes
Example:
stx::usize buffer_size = 4096;
stx::usize count = array.size();
stx::usize bytes_read = read(fd, buffer, sizeof(buffer));
isize
using isize = std::ptrdiff_t;
Signed size/difference type, represents the result of pointer subtraction. Platform-dependent (same size as pointers).
Pointer differences, signed offsets, iterator arithmetic
Example:
stx::isize offset = ptr2 - ptr1;
stx::isize delta = -100;
Pointer-Sized Integer Types
Integer types guaranteed to be the same size as pointers, suitable for storing addresses.
uptr
using uptr = std::uintptr_t;
Unsigned integer type capable of storing a pointer value. Used for address arithmetic and manipulation.
Platform pointer size (32 or 64 bits)
Address storage, pointer arithmetic, memory mapping
Example:
int* ptr = &value;
stx::uptr addr = reinterpret_cast<stx::uptr>(ptr);
stx::uptr base_address = 0x140000000;
// Address arithmetic
stx::uptr aligned = (addr + 15) & ~15; // Align to 16 bytes
iptr
using iptr = std::intptr_t;
Signed integer type capable of storing a pointer value. Less commonly used than uptr, but useful when signed arithmetic is needed.
Platform pointer size (32 or 64 bits)
Signed address offsets, relative addressing
Example:
stx::iptr relative_offset = target_addr - base_addr;
if (relative_offset < 0) {
// Handle backward reference
}
Complete Usage Example
#include <lbyte/stx/core.hpp>
namespace stx = lbyte::stx;
// Binary file header structure
struct FileHeader
{
stx::u32 magic; // Magic number
stx::u16 version; // Format version
stx::u16 flags; // Feature flags
stx::u64 file_size; // Total file size
stx::uptr base_address; // Preferred load address
};
// Process memory region
void process_region(void* base, stx::usize size)
{
stx::uptr addr = reinterpret_cast<stx::uptr>(base);
stx::usize remaining = size;
while (remaining > 0) {
stx::usize chunk = std::min(remaining, stx::usize{4096});
// Process chunk...
remaining -= chunk;
addr += chunk;
}
}
// Calculate aligned size
stx::usize align_size(stx::usize size, stx::usize alignment)
{
return (size + alignment - 1) & ~(alignment - 1);
}
Design Rationale
Explicit type names prevent accidental mixing of semantically different values (e.g., u32 vs i32).
Fixed-width types guarantee consistent behavior across platforms, critical for binary parsing and serialization.
Short, clear names (u32 instead of std::uint32_t) reduce visual noise while maintaining clarity.
Direct aliases to standard types ensure stable binary interfaces and interoperability.
All types are simple aliases with no runtime cost or additional memory usage.
Best Practices
- Use fixed-width types when exact bit width matters (binary formats, network protocols, serialization)
- Use usize/isize for sizes, counts, and container operations
- Use uptr/iptr for address manipulation and pointer arithmetic
- Avoid mixing signed and unsigned types in arithmetic operations
- Prefer explicit casts when converting between different width types