Today you can still work with (say) TI DSP chips that spit complex FFT pipelines results once per cycle and have absolutely no 8-bit hardware addressing or masking abilities as they're lean mean RISC optimised machines for pure 32 or 64 bit floating point operations.
They have C compilers and CHAR_BIT==32 (or 64).
* C preprocessor - it's a text substition operation that can be non standard
* C "the language" - just the syntax folks, no library functions here.
* C "the standard library" - for many of us the K&R stdlib was just a proof of concept example of how to code a library, feel free to ditch it and write up your own string handling, for example.
Which brings us to, say, a multi channel marine seismic processing system that has an IBM PC type design with a custom motherboard that has six TI DSP boards slotted in and you're writing code for the user interface to a real time signal aquisition and processing system and writing onboard code for the numerical processing on the DSP boards.
Now, each board handles a streamer cable, each cable has a number of microphones, an external boomer in the water is triggered and the reflective soundwaves from the ocean floor, and the soundwaves that penetrate the seafloor and later also partially reflected by density change layers, are all captured by the microphones.
You have keyboard+mouse I/O between the real time window manager user interface, shared memory I/O between the PC memory and memory on the DSP cards, analogue soundwaves going to sample ports on the DSP cards, block memory I/O going from the PC to a SEG-9 tape recorder, prepared lines of memory going to a plotter to build an image ...
There's a lot going on.
But, as far as the code compiled for the DSP boards, that mostly handles I/O by linking reaction code to interrupt triggers - when the sampling hardware interrupts to signal another bit of soundwave from microphone[i] is ready, that's stashed in a FiFo queue to be pushed into the DSP handling pipe and to be saved in a raw sample buffer.
When a raw sample buffer is full an interrupt is triggered to take the entire buffer via DMA transfer to by handled PC side by sending it to the SEG-9 tape "of (raw) record", when a processed sample buffer is full an interrupt is triggered for a different type of DMA trandfer that takes processed data to display, printer, another SEG-9 track for processed data.
Not much of this is the standard C library, so you can see why you might write your own low level handling.
Originaly using anonymous unions & placing largest bit count variable as first item in union was the context needed to align the "char" correctly -- vs. casting.
Technically, can point at anything in an unaligned manner, just need to align access to machines address boundary to use a "fetch the value of a complete valid memory alignment address". One can hand roll the appropriate shifts/masking to get at the set of bits loaded (which usually let compiler do). Awk and settable end of line marker good way to safely visualize this.