Operazioni bit a bit in pratica: AND, OR, XOR, shift, maschere
Apri una vecchia migrazione PostgreSQL e vedi permissions & 0b100. Un collega rilascia un sistema di feature flag che impacchetta 32 booleani in un singolo intero. Un calcolo di sottorete Kubernetes restituisce 192.168.1.0/24 e devi estrarre l’indirizzo di rete via codice. Tre situazioni, una sola competenza sottostante: le operazioni bit a bit.
La maggior parte degli sviluppatori applicativi non ha mai bisogno di ricorrere a & o ^ in una web app, finché all’improvviso ne hanno bisogno. Questa guida illustra i sei operatori bit a bit, il complemento a due, nove pattern da memorizzare e le trappole specifiche di ogni linguaggio che ti morderanno (specialmente in JavaScript). Il codice è in JS, Python, Go e C, e ogni esempio è eseguibile.
Apri il nostro Convertitore di basi in un’altra scheda. Diverse sezioni ti invitano a digitare un numero e osservare il pattern dei bit cambiare.
Perché le operazioni bit a bit contano ancora nel 2026
I linguaggi di alto livello non hanno reso obsolete le operazioni bit a bit. Hanno solo nascosto dove queste operazioni avvengono. Alcuni posti in cui ci stai facendo affidamento oggi, che tu te ne renda conto o no:
- La row-level security di PostgreSQL usa una bitmap di privilegi ACL (
SELECT,INSERT,UPDATE,DELETE, …) impacchettati in un intero. - Le capabilities di Linux sostituiscono il vecchio modello root-o-niente con oltre 40 bit di permesso che combini con
|. - Gli header di algoritmo JWT codificano l’algoritmo di hash in un piccolo campo dove il confronto a livello di bit è comune nello strato della libreria.
- Snowflake, ULID e UUIDv7 impacchettano timestamp, ID macchina e numero di sequenza in un singolo intero a 64 o 128 bit usando shift a sinistra.
BITCOUNTeBITOPdi Redis espongono primitive bit a bit direttamente al codice applicativo per la stima di cardinalità e il bucketing A/B.- L’image processing legge pixel RGBA a 32 bit ed estrae i canali con
&e>>.
Le operazioni bit a bit restano O(1) a livello di istruzione CPU. Quando impacchetti 32 booleani in un intero, risparmi 31 byte di memoria, e (più importante) puoi controllare “uno qualsiasi di questi 32 flag impostato” con un singolo test != 0.
Le basi binarie di cui hai bisogno prima
Questa guida assume che tu sappia già come funziona il binario. Se hai bisogno di un ripasso, leggi prima la nostra Guida alla conversione delle basi numeriche e poi torna qui.
Un rapido controllo del vocabolario prima di iniziare:
- Un bit è uno 0 o un 1.
- Un nibble è di 4 bit (una cifra esadecimale).
- Un byte è di 8 bit.
- Una word è tipicamente di 32 o 64 bit, a seconda della tua CPU.
Gli interi nella maggior parte dei linguaggi hanno larghezze fisse: 8, 16, 32, 64. La larghezza conta molto per le operazioni bit a bit perché gli shift possono spingere bit fuori dal bordo, e il bit di segno si trova nella posizione più a sinistra degli interi con segno.
Provalo ora. Apri il Convertitore di basi, inserisci 170 come decimale e guarda l’output binario. Dovresti vedere 10101010, un pattern alternato a cui torneremo più volte sotto.
I sei operatori bit a bit
Ogni linguaggio mainstream ti dà gli stessi sei operatori, talvolta con leggere differenze di sintassi. I simboli &, |, ^, ~, <<, >> funzionano in JavaScript, Python, Go, Rust, C, C++, Java e C# senza modifiche. JavaScript ne aggiunge uno extra: >>>, lo shift a destra senza segno.
AND (&): filtro di bit
Il bit di output è 1 solo se entrambi i bit di input sono 1.
| A | B | A & B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Pensa ad AND come a una porta: solo i bit impostati in entrambi gli operandi sopravvivono. L’uso più comune è il masking, mantenere alcuni bit e azzerare gli altri.
// Estrai i 4 bit bassi (il nibble più a destra)
const value = 0b11010110; // 214
const low4 = value & 0x0F; // 0b00000110 = 6
// Verifica se un numero è dispari
const isOdd = (n) => (n & 1) === 1;
isOdd(7); // true
isOdd(42); // false
# Lo stesso in Python
value = 0b11010110
low4 = value & 0x0F # 6
def is_odd(n):
return (n & 1) == 1
OR (|): impostatore di bit
Il bit di output è 1 se uno qualsiasi dei bit di input è 1.
| A | B | A | B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
OR combina i flag. Se hai READ = 1, WRITE = 2, EXECUTE = 4, allora READ | WRITE è 3, con entrambi i permessi abilitati.
const READ = 0b001;
const WRITE = 0b010;
const EXEC = 0b100;
const rw = READ | WRITE; // 0b011 = 3
READ, WRITE, EXEC = 0b001, 0b010, 0b100
rw = READ | WRITE # 3
XOR (^): commutatore di bit
Il bit di output è 1 se i bit di input differiscono.
| A | B | A ^ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
XOR ha tre proprietà algebriche che alimentano alcuni dei trucchi più ingegnosi dell’informatica:
a ^ a = 0: qualsiasi cosa in XOR con se stessa si annulla.a ^ 0 = a: XOR con zero è l’identità.a ^ b ^ a = b: XOR è il proprio inverso.
L’ultima proprietà è il motivo per cui XOR appare nei controlli di parità, nei cifrari a flusso e nella famigerata domanda da colloquio “trova l’unico numero non duplicato in un array”.
// Trova l'unico numero univoco in un array dove ogni altro numero appare due volte
const findUnique = (arr) => arr.reduce((a, b) => a ^ b, 0);
findUnique([4, 1, 2, 1, 2]); // 4
from functools import reduce
from operator import xor
find_unique = lambda arr: reduce(xor, arr, 0)
find_unique([4, 1, 2, 1, 2]) # 4
NOT (~): invertitore di bit
L’unario ~ inverte ogni bit: 0 diventa 1, 1 diventa 0.
~0b00001111 // -16 (JavaScript converte a 32 bit con segno)
~5 // -6
~5 # -6
// Go usa ^ come NOT bit a bit unario, attenzione
var x int8 = 5
fmt.Println(^x) // -6
Il risultato di ~5 è -6 in ogni linguaggio mainstream, e questo sorprende i principianti. Il motivo è il complemento a due, che copriamo nella prossima sezione. Per ora, sappi solo che ~x equivale a -(x + 1) in qualsiasi linguaggio che usa il complemento a due per i negativi (cioè tutti).
Shift a sinistra (<<): moltiplicatore per potenze di due
x << n sposta ogni bit di x a sinistra di n posizioni, riempiendo di zeri a destra. Matematicamente, questo moltiplica per 2ⁿ.
1 << 0 // 1 (2^0)
1 << 1 // 2 (2^1)
1 << 3 // 8 (2^3)
1 << 10 // 1024 (2^10 = 1 KiB)
// Costruzione di bit flag
const FLAG_ADMIN = 1 << 0;
const FLAG_EDITOR = 1 << 1;
const FLAG_REVIEWER = 1 << 2;
La cosa comoda di 1 << n è che crea un numero con un singolo bit impostato in posizione n. Quel bit diventa un flag.
Attenzione all’overflow. In JavaScript, 1 << 31 è -2147483648 (non 2147483648) perché gli operatori bit a bit di JavaScript lavorano su interi a 32 bit con segno.
Shift a destra (>> vs >>>): divisione o riempimento?
Lo shift a destra sposta i bit a destra. La domanda è cosa riempie le posizioni più a sinistra lasciate vuote.
>>(shift aritmetico a destra) preserva il bit di segno. I numeri negativi restano negativi.>>>(shift logico o senza segno a destra) riempie con zeri. Solo JavaScript ha questo come operatore dedicato.
-8 >> 1 // -4 (bit di segno preservato)
-8 >>> 1 // 2147483644 (bit di segno trattato come bit di dato)
8 >> 1 // 4
8 >> 2 // 2
In C, se >> è aritmetico o logico per i tipi con segno è definito dall’implementazione. La maggior parte dei compilatori fa l’aritmetico, ma non fare affidamento su questo senza verificarlo. Go richiede che le quantità di shift siano interi senza segno e tratta i tipi con e senza segno esplicitamente. Python non ha >>> perché non ha interi a larghezza fissa.
Complemento a due: come i computer rappresentano i negativi
Se i bit sono solo 0 e 1, come si codifica -5? La risposta su cui il mondo si è accordato negli anni ‘60 è il complemento a due, e ogni CPU moderna lo usa.
L’approccio ingenuo (riservare un bit per il segno) ha due problemi. Primo, ti ritrovi sia con +0 che con -0, il che è imbarazzante. Secondo, i circuiti di addizione e sottrazione devono controllare il bit di segno, rendendo l’hardware più complesso. Il complemento a due risolve entrambi.
La regola è breve:
- Prendi la rappresentazione binaria positiva.
- Inverti ogni bit (questo è il “complemento a uno”).
- Aggiungi 1.
Esempio pratico, codifica di -5 in complemento a due a 8 bit:
5 in binario: 0000 0101
inverti tutti i bit: 1111 1010 (questo è -6 in complemento a due!)
aggiungi 1: 1111 1011 ← questo è -5
Verifica con il nostro convertitore di basi: inserisci 251 (decimale) nel Convertitore di basi con base 10, e l’output binario è 11111011. In un contesto a 8 bit con segno, 11111011 è -5. In un contesto a 8 bit senza segno, lo stesso pattern di bit è 251. I bit sono identici; l’interpretazione differisce.
Questo spiega la sorpresa precedente di ~5 = -6. Il NOT bit a bit inverte i bit, il che ti dà il complemento a uno. Il complemento a due è il complemento a uno più 1. Quindi:
~x = -(x + 1) // identità in qualsiasi linguaggio a complemento a due
~5 = -6
~(-3) = 2
Per interi con segno a n bit, l’intervallo rappresentabile è da -2ⁿ⁻¹ a 2ⁿ⁻¹ − 1. Un intero con segno a 8 bit copre da -128 a 127. Un intero con segno a 32 bit copre approssimativamente da -2.1 miliardi a +2.1 miliardi.
Pattern essenziali di manipolazione dei bit
Questi nove pattern coprono forse il 95% della manipolazione di bit che scriverai mai. Memorizzali e li riconoscerai ovunque nel codice di sistema.
Imposta un bit: x | (1 << n)
Accendi il bit n, lascia gli altri bit invariati.
let flags = 0b0100;
flags = flags | (1 << 0); // 0b0101
Cancella un bit: x & ~(1 << n)
Spegni il bit n, lascia gli altri bit invariati. ~(1 << n) è una maschera con ogni bit impostato eccetto il bit n.
let flags = 0b0111;
flags = flags & ~(1 << 1); // 0b0101
Commuta un bit: x ^ (1 << n)
Inverti il bit n indipendentemente dal suo stato corrente.
let flags = 0b0100;
flags = flags ^ (1 << 2); // 0b0000
flags = flags ^ (1 << 2); // 0b0100 di nuovo
Verifica un bit: (x >> n) & 1
Restituisce 1 se il bit n è impostato, 0 altrimenti. Forma equivalente: (x & (1 << n)) !== 0.
const flags = 0b0101;
const isBit2Set = (flags >> 2) & 1; // 1
Isola il bit impostato più basso: x & -x
Produce un valore con solo il bit 1 più a destra di x mantenuto. Il trucco funziona perché -x in complemento a due è ~x + 1, che inverte ogni bit fino a e incluso il bit impostato più basso.
const x = 0b10110100;
const lowest = x & -x; // 0b00000100 = 4
Questo è il trucco fondamentale dietro i Fenwick tree (Binary Indexed Tree) per somme prefisso O(log n).
Conta i bit impostati (popcount)
Contare il numero di bit 1 in un intero. La maggior parte dei linguaggi ora ha una funzione nativa:
// JavaScript (BigInt o manuale)
const popcount = (n) => {
let count = 0;
while (n) { count += n & 1; n >>>= 1; }
return count;
};
popcount(0b10110100); // 4
# Python 3.10+
(0b10110100).bit_count() # 4
// Go
import "math/bits"
bits.OnesCount(0b10110100) // 4
Scambio XOR senza variabile temporanea
Un classico trucco da festa: scambia due interi senza una terza variabile. Non usarlo mai in produzione (è più lento di una variabile temporanea e si rompe se a e b puntano alla stessa posizione di memoria), ma vale la pena capirlo.
let a = 5, b = 9;
a = a ^ b; // a = 5 ^ 9
b = a ^ b; // b = (5 ^ 9) ^ 9 = 5
a = a ^ b; // a = (5 ^ 9) ^ 5 = 9
// a = 9, b = 5
Rileva potenza di due: (x & (x - 1)) === 0
Una potenza di due ha esattamente un bit impostato. Sottrarre 1 spegne quel bit e imposta ogni bit più basso. Fare l’AND dà zero solo per le potenze di due (e 0 stesso, quindi proteggi con x > 0).
const isPow2 = (x) => x > 0 && (x & (x - 1)) === 0;
isPow2(16); // true
isPow2(17); // false
Verifica rapida di disparità: x & 1
Più veloce di x % 2 in alcuni linguaggi, identico in altri dopo l’ottimizzazione del compilatore. Vale la pena nei loop intensivi o quando la leggibilità non conta.
const isOdd = (x) => (x & 1) === 1;
Bitmask flag in codice reale
I pattern qui sopra appaiono nel codice di produzione ogni giorno. Ecco quattro posti dove li incontrerai.
Feature flag in 32 booleani
Invece di una struct di 32 campi booleani, impacchettali in un singolo intero:
const FLAGS = {
DARK_MODE: 1 << 0,
NEW_NAV: 1 << 1,
AI_SUGGESTIONS: 1 << 2,
BETA_EDITOR: 1 << 3,
// ... fino a 1 << 31
};
let userFlags = 0;
userFlags |= FLAGS.DARK_MODE | FLAGS.AI_SUGGESTIONS; // opt in
if (userFlags & FLAGS.AI_SUGGESTIONS) {
showSuggestions();
}
userFlags &= ~FLAGS.DARK_MODE; // opt out
Questo memorizza 32 booleani in 4 byte e ti permette di interrogare qualsiasi sottoinsieme con un singolo AND. I database adorano questo pattern perché è una colonna invece di 32.
Permessi di file Unix
chmod 755 è bit a bit. Le tre cifre ottali si mappano a tre triple di bit:
7 = 111 (proprietario: rwx)
5 = 101 (gruppo: r-x)
5 = 101 (altri: r-x)
Provalo: apri il Convertitore di basi, imposta la sorgente su ottale, inserisci 755 e guarda l’output binario 111101101. È letteralmente come il filesystem memorizza il campo dei permessi.
Impostando solo “scrittura del gruppo”:
const perms = 0o755;
const withGroupWrite = perms | 0o020; // 0o775
Mascheramento di sottorete IP
Dato 192.168.1.10/24, estrai l’indirizzo di rete facendo l’AND con la maschera:
const ip = 0xC0A8010A; // 192.168.1.10
const mask = 0xFFFFFF00; // 255.255.255.0 (/24)
const network = ip & mask; // 0xC0A80100 = 192.168.1.0
ID impacchettati: Snowflake
Lo Snowflake di Twitter impacchetta timestamp, ID macchina e sequenza in un intero a 64 bit:
┌─ 1 bit ─┬─── 41 bit ────┬─ 10 bit ──┬─ 12 bit ──┐
│ segno │ timestamp │ macchina │ seq │
└─────────┴───────────────┴───────────┴───────────┘
Codificare un ID sono due shift e due OR:
const id = (BigInt(timestamp) << 22n) |
(BigInt(machineId) << 12n) |
BigInt(sequence);
Decodificare è il contrario: shift a destra e maschera. Per una panoramica completa su quando scegliere Snowflake vs ULID vs UUIDv7, vedi il nostro confronto degli ID distribuiti.
Trappole tra linguaggi
JavaScript: la trappola della coercizione a 32 bit
JavaScript converte gli operandi a interi con segno a 32 bit prima di ogni operazione bit a bit, poi converte il risultato di nuovo in Number. Qualsiasi valore sopra 2³¹ − 1 = 2147483647 va in overflow:
2147483647 | 0 // 2147483647 (ancora ok)
2147483648 | 0 // -2147483648 (in overflow!)
4294967295 | 0 // -1 (tutti i bit impostati, interpretati con segno)
Per il lavoro a 64 bit, usa BigInt. Ha operatori bit a bit indipendenti senza limiti di larghezza:
(2n ** 40n) | 1n // 1099511627777n
Bug di precedenza degli operatori
Questo è uno dei bug bit a bit del mondo reale più comuni:
// Buggato: si legge come (x & (1 == 0)) perché == lega più stretto di &
if (x & 1 == 0) { /* ... */ }
// Corretto: parentesi
if ((x & 1) == 0) { /* ... */ }
Gli operatori di confronto legano più stretti di AND/OR/XOR bit a bit in C, JavaScript, Python, Go e nella maggior parte dei discendenti. Metti le parentesi nel dubbio.
Tabella di confronto tra linguaggi
| Linguaggio | Coercizione di larghezza | >> negativo | Supporto BigInt |
|---|---|---|---|
| JavaScript | Forza a 32 bit con segno; >>> è senza segno | aritmetico | BigInt ha operatori separati |
| Python | Precisione arbitraria; nessuna larghezza fissa | aritmetico | Nativo |
| Go | Stretto; la quantità di shift deve essere senza segno | aritmetico per tipi con segno | math/big |
| C/C++ | Segue il tipo; int, unsigned, ecc. | definito dall’implementazione per i con segno | Nessuno integrato |
| Rust | Stretto; va in panic su overflow in debug | aritmetico per tipi con segno | u128 / crate esterni |
Il twist a larghezza infinita di Python
Gli interi Python non hanno larghezza fissa, quindi la logica del complemento a due si estende “infinitamente” a sinistra. È per questo che ~5 è -6 (non 250 o 65530): Python tratta il risultato come un intero negativo, non come un pattern di bit a larghezza fissa. Se hai bisogno di semantica wrap-around, maschera esplicitamente:
# Simula NOT a 8 bit
(~5) & 0xFF # 250
Verifica della realtà delle prestazioni nel 2026
La saggezza comune dice che le operazioni bit a bit sono “sempre più veloci”. Nel 2026, è vero a metà.
I compilatori fanno già le riscritture ovvie. Gli ottimizzatori moderni trasformano x * 2 in x << 1 automaticamente. Scrivere x << 1 nel codice applicativo per la velocità è cargo-cult performance tuning. Non aiuta, e danneggia la leggibilità.
Dove il codice bit a bit vince genuinamente:
- Loop intensivi nel codice numerico: popcount, conteggi di zeri iniziali e finali, motori di scacchi a bitboard.
- Strutture dati compatte: filtri di Bloom, roaring bitmap, Fenwick tree.
- Registri hardware e I/O mappato in memoria: codice embedded, kernel, firmware.
- Primitive crittografiche: AES, ChaCha20 e SHA sono tutti costruiti da XOR, rotazioni e shift.
- Compressione e decompressione: codifica Huffman, run-length, interi impacchettati.
- Motori di database: indici bitmap, formati a colonne impacchettati come la codifica a dizionario di Parquet.
Dove non aiuta: sostituire x % 2 con x & 1 in una funzione di logica di business che gira due volte per richiesta. L’accelerazione è non misurabile; il costo di leggibilità è reale.
L’unico caso in cui la manipolazione di bit vince sempre è il footprint di memoria. Impacchettare 32 flag in un int risparmia 31 byte rispetto a 32 booleani. Su larga scala (milioni di record utente, miliardi di eventi) è la differenza tra un layout cache-friendly e un workload che fa thrashing su L2.
Cheat sheet di riferimento rapido
| Operazione | Operatore | Esempio | Risultato | Uso tipico |
|---|---|---|---|---|
| AND | & | 0b1100 & 0b1010 | 0b1000 | Maschera/estrai bit |
| OR | | | 0b1100 | 0b1010 | 0b1110 | Combina flag |
| XOR | ^ | 0b1100 ^ 0b1010 | 0b0110 | Commuta / rileva differenza |
| NOT | ~ | ~0b1100 | ...11110011 | Inverti per maschera |
| Shift a sinistra | << | 1 << 3 | 8 | Moltiplica per 2ⁿ |
| Shift a destra | >> | 16 >> 2 | 4 | Dividi per 2ⁿ (con segno) |
| Shift a destra senza segno (JS) | >>> | -1 >>> 0 | 4294967295 | Tratta come senza segno |
Imposta bit n | | | x | (1 << n) | Accendi bit | |
Cancella bit n | & ~ | x & ~(1 << n) | Spegni bit | |
Commuta bit n | ^ | x ^ (1 << n) | Inverti bit | |
Verifica bit n | & | (x >> n) & 1 | 0 o 1 | Testa bit |
| Bit impostato più basso | & - | x & -x | Isola bit | |
| È potenza di 2 | & | x > 0 && (x & (x-1)) == 0 | bool | Testa potenza |
FAQ
Qual è la differenza tra AND logico (&&) e bit a bit (&)?
L’AND logico opera su valori booleani interi e cortocircuita, quindi false && expr non valuta mai expr. L’AND bit a bit opera sui singoli bit di interi e valuta sempre entrambi i lati. Usa && per le condizioni, & per la manipolazione di bit.
Perché ~1 equivale a -2 nella maggior parte dei linguaggi?
Il NOT bit a bit su 1 inverte ogni bit producendo il complemento a uno. Nella rappresentazione di interi a complemento a due, invertire tutti i bit di x dà -(x + 1), quindi ~1 equivale a -2, ~0 equivale a -1, e ~(-1) equivale a 0. Questa identità vale in JavaScript, Python, Go, C, Rust e in ogni altro linguaggio che memorizza interi con segno in complemento a due.
x << 1 è davvero più veloce di x * 2?
Non in pratica. Ogni compilatore moderno riconosce x * 2 ed emette la stessa istruzione di shift a livello macchina, quindi i benchmark non mostrano differenze misurabili su x86 o ARM. Usa x * 2 per la leggibilità; riserva << per i casi in cui stai intenzionalmente pensando in termini di bit, come costruire una bitmask o impacchettare ID strutturati.
JavaScript supporta operazioni bit a bit a 64 bit?
JavaScript non supporta operazioni bit a bit a 64 bit con gli operatori standard &, |, ^, <<, >>, perché quelli forzano gli operandi a interi con segno a 32 bit prima dell’operazione. Per valori a 64 bit o più grandi, usa letterali BigInt come 1n << 40n, che danno operazioni bit a bit a precisione arbitraria con i propri operatori corrispondenti.
Come conto efficientemente il numero di bit impostati?
Usa l’integrato del tuo linguaggio: bits.OnesCount in Go, Integer.bitCount in Java, .bit_count() in Python 3.10+, intrinseci popcount in C/C++. Questi si mappano a una singola istruzione CPU POPCNT su x86 e ARM moderni.
Quando dovrei usare bitmask flag invece di una struct di booleani?
Usa bitmask flag quando hai bisogno di memorizzare molti booleani in modo compatto (database, protocolli di rete, formati di file) o testare combinazioni rapidamente con un singolo AND come flags & REQUIRED_MASK. Preferisci una struct di booleani quando i campi hanno tipi diversi, quando hai bisogno di output di debug descrittivo, o quando la leggibilità conta più di pochi byte di memoria.
Cosa succede quando faccio uno shift di più della larghezza in bit?
Indefinito in C/C++. In JavaScript, il conteggio dello shift è preso mod 32, quindi 1 << 32 è 1, non 0. In Python, non c’è larghezza, quindi 1 << 100 è solo un intero più grande. Non fare mai affidamento sul comportamento di overshift; maschera tu stesso il conteggio dello shift se serve.
Perché ~5 di Python dà -6 invece di 2?
Gli interi Python non hanno larghezza fissa, quindi il complemento a due si estende concettualmente all’infinito. ~5 equivale a -(5 + 1) = -6, lo stesso di ogni altro linguaggio a complemento a due. Se vuoi il valore “invertito” a 8 bit 250, maschera: (~5) & 0xFF.
La crittografia XOR è sicura?
Un one-time pad con una chiave veramente casuale lunga quanto il messaggio è informazionalmente teoricamente inviolabile. Riutilizzare la stessa chiave su più messaggi è catastroficamente insicuro, e la “crittografia” XOR standard con una chiave breve ripetuta è banalmente violabile. I cifrari reali come AES e ChaCha20 usano XOR internamente, ma come un passo tra molti.
Come rappresento un numero negativo usando il complemento a due a mano?
Scrivi il valore positivo in binario alla larghezza target, inverti ogni bit, poi aggiungi 1. Esempio: -5 in 8 bit = 00000101 → inverti a 11111010 → aggiungi 1 → 11111011. Verifica con il nostro Convertitore di basi convertendo 251 (l’interpretazione senza segno di 11111011) e confermando che ottieni 11111011.
Strumenti correlati e ulteriori letture
- Convertitore di basi: digita qualsiasi numero e osserva i bit
- Guida alla conversione delle basi numeriche: lettura prerequisita su binario, ottale ed esadecimale
- UUID v4 vs v7 vs ULID vs Snowflake: impacchettamento di bit negli ID distribuiti
- Best practice di sicurezza: bitmap di permessi e le loro insidie