Why a machine counts in twos
In the foundations rung we pictured memory as one long numbered street of mailboxes, each holding a number. Now we open a mailbox and ask the obvious question: how is a number actually stored in there? The answer is the bedrock of everything else in this rung. Down at the silicon, a computer has no concept of the digit 7, or of the colour blue, or of the letter A. It has only switches — tiny circuits that are either carrying current or not, on or off, high or low. Each such switch is one bit, the smallest unit of information there is: a single yes-or-no.
One switch can only say two things, so to count past 1 you line up several switches and read them as a single number. This is exactly how you already count in everyday decimal, you simply never think about it. In decimal each column is worth ten times the one to its right: the number 305 means 3 hundreds, 0 tens, 5 ones, because the place values are powers of ten. Binary plays the identical game with one change — each column is worth two times the one to its right, because each switch has only two states instead of ten. The place values become 1, 2, 4, 8, 16, 32, and so on: the powers of two.
So reading a binary number is just adding up the place values where a switch is on. Take the pattern 1011. From the right, the columns are worth 1, 2, 4, 8. The on bits sit in the 8, 2 and 1 columns, so 1011 is 8 + 2 + 1 = 11 in decimal. That is the whole trick of binary: a row of switches, place values doubling leftward, add up the ones. Nothing is hidden; it is ordinary counting on a base-two abacus.
binary: 1 0 1 1 place: 8 4 2 1 value: 8 + 0 + 2 + 1 = 11 (decimal) 0011 0010 -> 32 + 16 + 2 = 50
Bits gather into bytes
A lone bit is too small to be useful, so machines bundle them. The bundle that won is eight bits, and we call it a byte — the unit in which memory is addressed and sold. Eight switches give 2^8 = 256 distinct patterns, from 0000 0000 up to 1111 1111, which means one byte can represent any of 256 different values: read as an unsigned integer, that is 0 through 255. This 0-to-255 range is worth memorising; it is the reason an old-school colour channel or a `char` so often tops out at 255.
Half a byte — four bits — comes up so often it has its own name, a nibble (yes, really, a small bite). One nibble holds 2^4 = 16 patterns, the values 0 through 15. Hold on to that 16: it is the hinge that connects binary to the hexadecimal we are about to meet. Larger bundles also have names you will use constantly. The natural chunk a particular CPU likes to handle in one go — typically 4 or 8 bytes on the machines you will program — is its word. A 64-bit machine has a 64-bit (8-byte) word, which is why a plain `int` or a pointer is usually that size.
Hexadecimal: binary you can actually read
Binary is honest but exhausting to read: a single byte is eight digits, and a 32-bit value is a wall of thirty-two 1s and 0s your eye slides right off. So systems people almost never write raw binary by hand. Instead they write hexadecimal — base sixteen — and the reason it works so beautifully is that one nibble (four bits) maps to exactly one hex digit. Sixteen patterns, sixteen digits. We run out of ordinary digits at 9, so hex borrows the letters a through f for the values 10 through 15: a is 10, b is 11, c is 12, d is 13, e is 14, f is 15.
To keep hex from being mistaken for an ordinary number, C and most tools prefix it with 0x. So 0x1f is a hex value, while 1f alone is meaningless. Throughout these guides we write hex in lowercase with that prefix, as in 0x1f or 0x7fffffff. Converting a byte to hex needs no arithmetic at all once you see the nibble trick: split the eight bits into two nibbles, turn each into its single hex digit, done. The byte 0011 0010 splits into 0011 (which is 3) and 0010 (which is 2), giving 0x32. Read back the other way just as easily: 0x32 is the nibbles 3 and 2, i.e. 0011 0010.
- Take the byte's eight bits and split them down the middle into two nibbles of four bits each.
- Read each nibble as a number 0 to 15 by adding its place values (8, 4, 2, 1).
- Turn each value into its hex digit: 0 to 9 stay as themselves, 10 to 15 become a to f.
- Write the two hex digits side by side with a 0x prefix — that is your byte, e.g. 1110 1011 becomes 0xeb.
Now the payoff lands. Because two hex digits cover exactly one byte, hex is the natural language for talking about memory, and you will see it everywhere: addresses, masks, and raw byte dumps. One byte is always two hex digits, so a 32-bit (4-byte) value is always eight of them — which is why a value like 0x7fffffff is instantly recognisable as four bytes wide. When a debugger shows you `0x4011a0` for an address, or this rung's later guides write a conversion between bases, that compactness is exactly why hex, not binary, is the working notation.
Converting between the bases by hand
You rarely convert binary to hex with arithmetic, because the nibble grouping is instant. But going to and from decimal — the base humans think in — does take a small method, and it is worth doing by hand a few times so the magic dissolves. To turn a decimal number into binary, repeatedly halve it and write down the remainders. To go the other way, multiply out the place values, exactly as we did with 1011 earlier. Both directions are mechanical once you have seen them.
- Start with your decimal number, say 50, and divide by 2, noting quotient and remainder: 50 = 25 remainder 0.
- Divide the quotient again: 25 = 12 r1, then 12 = 6 r0, 6 = 3 r0, 3 = 1 r1, 1 = 0 r1. Stop when the quotient hits 0.
- Read the remainders from the LAST one to the first — bottom to top — to get the binary digits: 110010.
- Pad on the left to a full byte if you like (0011 0010) and group into nibbles to read off the hex: 0x32. Sanity-check by adding place values: 32 + 16 + 2 = 50.
That worked example walked decimal 50 all the way to 0x32 and back, and the round trip is the best possible proof that these are not three different numbers but one value wearing three costumes. Fifty things on a table are fifty things whether you label the pile 50, 0011 0010, or 0x32. The base is only the notation; the quantity underneath is the same. Internalising that — that a number and its written form are different — is half of what this rung is teaching, and it is the ground the next guides build signed numbers and floating point upon.
Where this leaves you
Step back and see what you have actually gained, because it is more than a parlour trick. You can now look at a byte three ways — as eight switches, as a decimal count, and as two hex digits — and slide between them at will. That fluency is the literacy on which the entire data-representation rung stands. Every remaining guide in this rung is, at heart, a new interpretation laid over the same rows of bits you can now read.
Here is the honest cliffhanger. Everything above quietly assumed our numbers were never negative — 0 and up only. But real programs subtract, and `5 - 8` ought to be -3. How do you store a minus sign when all you have is on/off switches with no slot for a symbol? There is a genuinely clever answer, two's complement, and unwrapping it is the whole job of guide 2. The bits you have learned to read are about to learn a second way of being read.