DevKitLab Logo DevKitLab
Bases numéricas / Hexadecimal / Binario

Hexadecimal, binario y decimal: leer los números que los programadores de verdad usan

Un color es #FF5733. Un modo de archivo es chmod 755. Una comprobación de permisos es flags & 0x04. Una constante es 0b1010, o 0xFF, o 255. Cada uno parece su propio dialecto, pero son un mismo número con ropa distinta —y la soltura que hace que todo deje de ser fricción es más pequeña de lo que parece: hex para bytes, binario para bits, decimal para humanos.

Te encuentras una y otra vez los mismos números con ropa distinta. Un color es #FF5733. Un modo de archivo es chmod 755. Una comprobación de permisos se lee flags & 0x04. Una constante es 0b1010, o 0xFF, o 255. Cada notación parece su propio dialecto, y cuando tienes que cruzar entre ellas —¿0xFF es de verdad 255?, ¿chmod 755 significa lo que creo?— echas mano de un conversor o cuentas con los dedos. La soltura que hace que todo esto deje de ser fricción es más pequeña de lo que parece, y empieza con una idea.

Aquí está: hex, binario y decimal no son tres clases de número —son tres formas de escribir el mismo número. 255, 0xFF y 0b11111111 son un valor en tres notaciones, igual que «quince», «15» y «XV» son un valor en tres notaciones. Un número no tiene una base; un número escrito la tiene. Así que la habilidad de verdad no es convertir —una herramienta lo hace de una tecla— sino saber por qué cambiarías: eliges la representación que hace visible la estructura del número. Hex cuando el número es en realidad un montón de bytes (un color, un hash, una dirección). Binario cuando los bits individuales cargan significado (flags, máscaras, hardware). Decimal cuando un humano solo necesita leer una cuenta.

Este artículo dedica un minuto a qué es una base —agrupar, no identidad—, luego a por qué un dígito hex es exactamente cuatro bits, lo que hace del hex una ventana compacta al binario. Después, los sitios donde de verdad los encuentras: colores, chmod, máscaras de bits. Y luego las operaciones bit a bit que solo cobran sentido cuando ves los bits, y las trampas —números con signo, orden de bytes— que muerden cuando no los ves.

La única idea: una base es cómo agrupas, no qué es el número

Todo número es una cuenta de cosas. Una base es solo el tamaño del cubo en el que las agrupas antes de empezar una columna nueva. En decimal (base 10) cada columna es una potencia de diez: 255 = 2×100 + 5×10 + 5×1. En hex (base 16) cada columna es una potencia de dieciséis, con dígitos 0–9 y luego A–F para diez a quince: 0xFF = 15×16 + 15×1 = 255. En binario (base 2) cada columna es una potencia de dos: 0b11111111 = 128+64+32+16+8+4+2+1 = 255. El mismo 255 cada vez. El valor es lo que es; la base solo decide cómo se deletrea —por eso «convertir hex a decimal» nunca cambia el número, solo tu vista de él.

Hex: una ventana compacta a los bytes

Por qué los programadores echan mano del hex a todas horas se reduce a una coincidencia limpia: 16 es 2⁴, así que un dígito hex es exactamente cuatro bits —un nibble— y dos dígitos hex son exactamente un byte (8 bits, 0–255, 0x000xFF). Ese alineamiento es todo el atractivo. Un byte escrito en decimal (77) no te dice nada de sus bits; el mismo byte en hex (0x4D) se parte limpio en dos nibbles, y cada nibble corresponde a cuatro bits que lees de un vistazo. Pruébalo con 0x2F: divídelo en los nibbles 2 y F, expande al byte completo 0010 1111 y suma las columnas que están a 1 —32 + 8 + 4 + 2 + 1 = 47. Así que el hex es en realidad binario para humanos —toda la estructura de bytes y bits, en la cuarta parte de los dígitos—. Por eso hashes, colores, direcciones de memoria y volcados de bytes se escriben en hex: son montones de bytes, y el hex muestra los bytes.

Binario: cuando los bits individuales cargan significado

A veces no quieres la vista compacta —quieres los bits mismos, porque cada uno significa algo—. Eso es binario, base 2, donde cada dígito es un solo bit: encendido o apagado, a 1 o a 0. Bajas a binario cuando un número no es una cantidad en absoluto sino un conjunto de interruptores independientes —un conjunto de permisos, un entero de feature flags, un registro de hardware donde el bit 3 habilita algo y el bit 6 significa «error»—. Ahí, 13 en decimal no dice nada útil, pero 0b1101 dice los bits 0, 2 y 3 están encendidos —que es la información real que el número llevaba.

Dónde los encuentras de verdad

Tres casos cotidianos clavan todo esto:

  • Los colores son tres bytes de hex. #FF5733 es FF 57 33 —rojo 0xFF (255), verde 0x57 (87), azul 0x33 (51), cada uno un byte de 0 a 255—. #RRGGBBAA añade un cuarto byte para la opacidad. Una vez que ves un color como tres bytes, #FFFFFF (todos los bytes al máximo → blanco) y #000000 (todo cero → negro) dejan de ser magia.
  • Los permisos Unix son octal —una tercera base. chmod 755 no es decimal ni hex; es base 8, y cada dígito es exactamente tres bits: r w x. 7 es 111 = lectura + escritura + ejecución; 5 es 101 = lectura + ejecución, sin escritura. Así que 755 es rwx r-x r-x para dueño / grupo / otros. El octal sobrevive aquí precisamente porque «tres bits por dígito» encaja con los tres bits de permiso. (El código moderno lo escribe 0o755.)
  • Los flags son bits que compruebas con aritmética de bits. Un conjunto de opciones empaquetadas en un entero, cada opción una potencia de dos para que ocupe exactamente un bit: READ = 1 (0b001), WRITE = 2 (0b010), EXEC = 4 (0b100). Los combinas con OR (READ | WRITE0b011), compruebas uno con AND (flags & WRITE es distinto de cero cuando el bit está puesto), y limpias uno con un AND contra el inverso. El 0x04 de flags & 0x04 es solo el bit 2 con ropa de hex.

Operaciones bit a bit: legibles en cuanto ves los bits

Funcionan bit a bit, y pasan de crípticas a obvias en el momento en que escribes los operandos en binario o hex:

  • AND (&) — 1 solo donde ambos son 1. Se usa para comprobar o enmascarar: x & 0xFF conserva el byte bajo y pone a cero el resto.
  • OR (|) — 1 donde cualquiera es 1. Se usa para poner bits: x | 0x04 enciende el bit 2.
  • XOR (^) — 1 donde los bits difieren. Se usa para alternar bits, y aparece en algunas sumas de verificación sencillas.
  • NOT (~) — invierte cada bit dentro del ancho fijo del valor, así que el resultado depende de cuántos bits tenga el tipo.
  • Desplazamientos (<<, >>) — deslizan los bits a izquierda o derecha. Para un valor sin signo y sin desbordamiento, x << 1 es ×2 y x << 8 sube un valor un byte entero; para un valor no negativo, x >> 4 tira los cuatro bits bajos. (En valores con signo un desplazamiento a la derecha puede extender el signo, y la regla exacta depende del lenguaje —así que apóyate en los desplazamientos para manipular bits sin signo.) Desplazar es cómo empaquetas y desempaquetas campos —(r << 16) | (g << 8) | b ensambla un color a partir de tres bytes separados.

Prueba 0b1100 & 0b1010 y la respuesta es a ojos vistas 0b1000; prueba 12 & 10 en decimal y es un acertijo. Esa es toda la razón para cambiar de representación antes de hacer aritmética de bits.

Las trampas que muerden

Dos sitios donde el cuadro limpio se filtra, ambos valen la pena:

  • Con signo frente a sin signo, y complemento a dos. Los mismos bits se leen como número sin signo o con signo. Las computadoras guardan los negativos en complemento a dos, donde —en una representación de ancho fijo— el bit superior actúa de signo, así que en complemento a dos de 8 bits el byte 0xFF es 255 sin signo pero -1 con signo. Este es el mecanismo tras el clásico desbordamiento de 32 bits: un contador con signo de 32 bits topa en 0x7FFFFFFF, y un incremento más lo pasaría hacia un negativo grande —por eso muchos sistemas Unix que guardan el tiempo en un entero con signo de 32 bits chocan con el problema del año 2038. (Cómo reacciona un lenguaje a ese desbordamiento varía: unos dan la vuelta, otros lanzan, otros lo dejan indefinido.)
  • Orden de bytes (endianness). Cuando un número abarca varios bytes, pueden disponerse big-endian (el más significativo primero) o little-endian (el menos primero). El valor 0x01020304 se guarda como 01 02 03 04 en una disposición big-endian y 04 03 02 01 en una disposición little-endian —así que un volcado de bytes que parece «al revés» normalmente no está corrupto, solo es little-endian.

Dos pequeñas comodidades para cerrar. Los prefijos 0x (hex), 0b (binario) y 0o (octal) existen para que un número escrito anuncie su base —0x10 es 16, 0b10 es 2, 10 es diez—. Y los ceros a la izquierda en hex o binario son solo anchura: 0x0F y 0xF son el mismo valor; el cero de más rellena hasta un byte completo por legibilidad.

La referencia rápida

Cuando un número en el mundo real parezca desconocido, ubícalo antes de calcular:

  1. Lee el prefijo. 0x hex, 0b binario, 0o (o un 0 inicial en C antiguo) octal, ninguno → decimal. Un # antes de seis dígitos hex → un color RGB.
  2. Ajusta la base a la estructura. Bytes (colores, hashes, direcciones) → hex. Bits independientes (flags, máscaras, registros) → binario. Una cuenta para humanos → decimal. Permisos → octal.
  3. Un dígito hex = 4 bits, dos = un byte. Ese único hecho convierte casi todo el hex a bits en tu cabeza, y de vuelta.
  4. Para aritmética de bits, cambia primero a binario o hex, y luego AND para comprobar o enmascarar, OR para poner, XOR para alternar, desplazamientos para mover campos.
  5. Vigila el signo y el orden de bytes cuando un valor parezca disparatado —un número enorme que debería ser pequeño suele ser un valor con signo leído como sin signo, o bytes en el otro orden de bytes—. (Esos pares %XX de una URL estropeada también son bytes hex —la misma soltura los lee.)

Para cualquier cosa más allá del cálculo mental —una máscara de 64 bits, una base rara, comprobar un valor en complemento a dos— un conversor de bases numéricas muestra hex, decimal, binario y octal lado a lado, para que veas el mismo valor en cada notación a la vez. Bajo todo ello está la única idea: son un mismo número con ropa distinta, y la soltura es solo saber qué atuendo hace visible la estructura.