Question of mine: how can you do this in C? (...)
You mean how can you define a 256-bit data type?
The general idea is that you express the number in a different base (depending on what data types you
do have available). For example, if all you had was (let's say)
unsigned char (assume that
CHAR_BIT == 8), and you wanted an unsigned 32-bit data type, then you could simulate one with a
struct (and your own functions to implement arithmetic and logic operations) by thinking in terms of a 4-digit number in base 256, rather than a 32-digit number in base 2. Same thing extends to thinking of a 256-bit number as a 16-digit number in base 65536, or as a 4-digit number in base 2**64, etc.
There are variations on this technique, but that's the basic idea.
Here's one implementation (in C, and assembly):
https://github.com/piggypiggy/fp256.
And here's (a piece of) a more specialized implementation from
libsecp256k1 (52-bit limbs instead of 64-bit ones):
https://github.com/bitcoin-core/secp256k1/blob/master/src/field_5x52_impl.h.