Why hexadecimal is everywhere in computing
Hexadecimal is convenient for one specific reason: 16 is 2⁴, so each hex digit maps to exactly four bits with no remainder. A byte is therefore always two hex digits, and converting between hex and binary is a per-digit substitution requiring no arithmetic.
That property is why hex appears wherever raw bytes do — colour codes, memory addresses, hashes, MAC addresses, character encodings. Decimal has no such alignment: 255 in decimal gives no indication that it is the largest value a byte can hold, while FF makes it obvious.
Octal survives mainly in Unix file permissions, where three bits map neatly to one digit and 755 compactly encodes read, write and execute for owner, group and others. It is otherwise largely historical, from architectures with word sizes divisible by three. Beware that a leading zero denotes octal in C and several other languages, so 010 is 8 — a genuine source of bugs in code handling zero-padded numbers.
Negative numbers and two's complement
Converting a negative number between bases is only well defined once you decide how negatives are represented. Modern hardware uses two's complement: the most significant bit indicates sign, and a negative value is stored as the bitwise complement of its magnitude plus one.
In eight bits, −1 is 11111111 and −128 is 10000000. The scheme is used because addition and subtraction work identically for signed and unsigned values, so the hardware needs one adder rather than two. Its asymmetry is a consequence: an 8-bit signed range is −128 to +127, with one more negative value than positive, so negating −128 overflows.
This is why a hex value such as FFFFFFFF is 4,294,967,295 read as unsigned and −1 read as signed. The bits are identical; only the interpretation differs, and a converter must be told which you mean.
Where conversions go wrong
Width matters as much as value. FF is 255 in eight bits and 255 in sixteen bits, but sign-extending an 8-bit −1 into 16 bits gives FFFF, not 00FF. Converting without knowing the width silently produces the wrong number for negative values.
Byte order is the other pitfall. Little-endian machines — x86 and most ARM configurations — store the least significant byte first, so the 32-bit value 0x12345678 appears in memory as 78 56 34 12. Network protocols conventionally use big-endian, which is why raw bytes read from a file or a socket often appear reversed.
Fractional values are the messiest case. Most decimal fractions have no finite binary representation, so 0.1 in binary repeats forever and must be truncated — the root of the familiar floating-point rounding surprises. Integer conversion between bases is exact; fractional conversion generally is not.