FirmGod

Hex / Binary / Decimal / ASCII Converter

Binary to decimal, decimal to hex, hex to ASCII — at 8, 16, 32 or 64 bits, with signed and unsigned readings and byte order both ways.

Range 0 to 4294967295

Prefixes and separators are ignored.

Try:

Bits

Click any bit to flip it. Numbering starts at bit 0 on the right.

bits 31–24
bits 23–16
bits 15–8
bits 7–0
Set bits: 24 of 32Positions: 31, 30, 28, 27, 26, 25, 23, 21, 19, 18, 16, 15, 13, 12, 11, 10, 9, 7, 6, 5, 3, 2, 1, 0

Bytes in memory

The same value as a little-endian machine and a big-endian one lay it out. Reading a buffer with the wrong order is what turns a sensible number into nonsense.

OrderBytesASCIIAs a value
Big endianDE AD BE EF····0xDEADBEEF
Little endianEF BE AD DE····0xEFBEADDE
Replaces the value with its byte-reversed form, for when a capture came off the wire the other way round.

All representations

Hexadecimal0xDEADBEEF
Hex, byte groupedDE AD BE EF
Decimal3735928559
Signed reading-559038737
Binary1101 1110 1010 1101 1011 1110 1110 1111
Octal33653337357
C literal0xDEADBEEFUL

Doing each conversion by hand

The tool does all of this instantly, but the arithmetic is worth knowing — partly because you will be reading a register value on a scope or in a log where there is nothing to paste into, and partly because knowing it is what lets you spot a wrong answer.

Binary to decimal

Each position is a power of two, counting from zero at the right. Add the powers where the bit is set. For 1011_0110: bits 1, 2, 4, 5 and 7 are set, so the value is 2 + 4 + 16 + 32 + 128 = 182. The quicker route for a byte is to split it into two nibbles and read each as a hex digit — 1011 is 11 and 0110 is 6, giving 0xB6, which is 11 × 16 + 6 = 182 again.

Decimal to hex

Divide by 16 and keep the remainders, last one first. 182 ÷ 16 is 11 remainder 6, and 11 ÷ 16 is 0 remainder 11, so the digits are 11 and 6 — 0xB6. For values that fit in a byte it is usually faster to go through binary: write the eight bits, split into nibbles, read each as a digit.

Hex to ASCII

Each byte is one character in the ASCII range 0x20 to 0x7E. 48 65 6C 6C 6F isHello. Anything below 0x20 is a control code rather than a printable character — 0x0A is a newline, 0x0D a carriage return, 0x00 the terminator that ends a C string — which is why the tool shows a dot in those positions rather than inventing a glyph. Bytes above 0x7F are not ASCII at all; what they mean depends on an encoding the bytes themselves do not carry.

Where this converter differs from a general-purpose one is everything below: it asks how wide the value is and whether it is signed, because in embedded work those two questions change the answer.

Why width and signedness belong in a converter

Most base converters treat what you type as an unbounded integer. That is fine for arithmetic homework and wrong for firmware, where a value is a register of a known size and its top bit may carry a sign. The number 0xFF is 255, or it is −1, and which one it is depends entirely on the width and interpretation you declared — not on the digits.

That is why the controls above come first. Change the width and the same pattern is re-read; change the interpretation and only the decimal column moves, because the bits never moved at all.

Two's complement, briefly

Signed integers are stored so that the top bit is worth a large negative amount rather than a large positive one. At 8 bits, bit 7 is worth −128 instead of +128, so the range runs from −128 to 127 rather than 0 to 255.

The practical rule for negating a value is to invert every bit and add one. Two properties follow, and both matter in practice: zero has exactly one representation, and addition works identically for signed and unsigned operands. The hardware adder does not need to know which you meant, which is why the distinction lives in your types and not in the silicon.

PatternUnsignedSigned (8-bit)
0x0000
0x7F127127
0x80128−128
0xFF255−1

Endianness is about memory, not about the number

A 32-bit value is a single number. It only acquires a byte order when it is written somewhere with addresses. Little-endian machines put the least significant byte at the lowest address; big-endian machines put the most significant byte there. Both hold the same value, and code that only ever does arithmetic never notices.

It becomes visible the moment bytes leave the CPU: a buffer sent over a UART, a struct written to flash, a packet on a network. Network protocols are defined big endian, so a little-endian host has to convert, which is what htons and htonl do. Getting this wrong is the classic cause of a value that reads as an absurd number rather than the temperature you expected.

The byte table above shows both layouts side by side, and the swap button rewrites the value as its reversed form for when a capture arrived the other way round.

Traps in C that this tool makes visible

Integer promotion

Anything narrower than int is promoted before arithmetic happens. Two uint8_t values of 200 and 100 add to 300, not 44, because the addition is performed in int. The truncation only occurs when the result is stored back into a narrow type — so an intermediate comparison sees a value that never existed in your variable.

Sign extension on widening

Widening a signed type replicates the sign bit. An int8_t holding −1 becomes0xFFFFFFFF when assigned to an int32_t, not 0x000000FF. When you want the raw bits rather than the value, cast through the unsigned type of the original width first:(uint32_t)(uint8_t)value.

Shifting past the width

Shifting a 32-bit value by 32 or more is undefined behaviour, and shifting a signed value left into or past the sign bit is too. Both compile without complaint and both do different things on different targets. If you are building a mask that might span the full width, do it in a type wider than the field.

Reading a hex dump

When a value arrives as bytes rather than as a number, set the width to match the field you are decoding, paste the bytes into the hex box, and read the two layouts. If one reading is a plausible engineering value and the other is not, you have found the byte order. The same technique settles most protocol disputes faster than re-reading the specification.

For values that are floats rather than integers, the IEEE 754 converterbreaks out the sign, exponent, and mantissa. For register pairs arriving over Modbus, theModbus register decoder covers all four word and byte orders devices use in practice.

Frequently asked questions

How do I convert binary to decimal?

Add the powers of two where a bit is set, counting from zero at the right. 1011_0110 has bits 1, 2, 4, 5 and 7 set, so it is 2 + 4 + 16 + 32 + 128 = 182. For a byte it is quicker to split it into nibbles and read each as a hex digit: 1011 is B, 0110 is 6, so 0xB6, which is 11 × 16 + 6 = 182.

How do I convert decimal to hex?

Divide by 16 and keep the remainders, last one first. 182 ÷ 16 is 11 remainder 6; 11 ÷ 16 is 0 remainder 11. The digits are 11 and 6, so 0xB6. Going through binary is usually faster for a byte — write the eight bits, split into nibbles, read each nibble as one hex digit.

Why does 0xFF show as −1?

Because at 8 bits with a signed interpretation the top bit is the sign. Two’s complement gives 0xFF the value −1, and the same pattern read unsigned is 255. Nothing about the bits changes; only how you agree to read them does. Switch the interpretation control above to see both.

What is the difference between big and little endian?

It is the order the bytes of a value sit at increasing memory addresses. A little-endian machine stores 0x12345678 as 78 56 34 12; a big-endian one stores it as 12 34 56 78. The value is identical in both — only the layout differs, which matters the moment bytes cross a bus, a file, or a network.

Which endianness does my part use?

x86, x86-64, and ARM in its usual configuration are little endian. Network protocols are defined big endian, which is why it is called network byte order. Some parts, notably older PowerPC and certain MIPS and ARM configurations, can be switched, so check the datasheet rather than assuming.

Why does my uint8_t arithmetic produce a signed result in C?

Integer promotion. Any operand narrower than int is promoted to int before the operation, so `uint8_t a = 200, b = 100; a + b` is computed as 300 in int, not wrapped to 44. Assigning back to a uint8_t truncates it, but an intermediate comparison sees the promoted value.

Why did my int8_t turn into 0xFFFFFFFF?

Sign extension. Widening a signed type copies the sign bit into the new high bits, so int8_t −1 becomes 0xFFFFFFFF as an int32_t rather than 0x000000FF. Cast through the unsigned type of the original width when you want the raw bits: (uint32_t)(uint8_t)value.

How do I write hex and binary literals in C?

Hex uses 0x and is standard everywhere. Binary literals written 0b1010 are a GCC and Clang extension that C23 standardises; older strict-C compilers reject them. Digit separators are a C++14 feature using apostrophes and are not available in C.