HOWTO · C

Come confrontare i bit in C

Questo articolo mostra come confrontare i bit in C.

In questa pagina

Le operazioni bit per bit sono fondamentali nella programmazione informatica, soprattutto quando si lavora con la manipolazione dei dati di basso livello. In C, esistono diversi metodi per confrontare singoli bit o gruppi di bit.

In questo articolo, esploreremo diverse tecniche insieme a esempi di codice per dimostrare ciascun metodo.

Implementare una funzione personalizzata utilizzando le operazioni XOR e AND bit per bit per il confronto di bit in C

L’operatore AND bit per bit (&) viene utilizzato per eseguire un confronto bit per bit tra i bit corrispondenti di due operandi. Questa operazione produce un nuovo valore in cui ciascun bit è impostato se e solo se i bit corrispondenti in entrambi gli operandi sono impostati.

Codice di esempio:

#include <stdio.h>

int main() {
  unsigned int num1 = 9;  // Binary representation: 1001
  unsigned int num2 = 6;  // Binary representation: 0110

  unsigned int result = num1 & num2;

  printf("Result: %u\n", result);  // Output: 0 (Binary: 0000)

  return 0;
}

Output:

Result: 0

In questo esempio, num1 e num2 sono inizializzati con i valori 9 e 6, rispettivamente. Questi valori sono rappresentati in binario come 1001 e 0110.

L’operazione AND bit per bit tra num1 e num2 (num1 & num2) produce 0000 in binario, che è 0 in decimale. Ciò significa che nessun bit corrispondente è impostato sia in num1 sia in num2.

Nel frattempo, l’operatore XOR bit per bit (^) viene utilizzato per eseguire un confronto bit per bit tra i bit corrispondenti di due operandi. Questa operazione produce un nuovo valore in cui ciascun bit è impostato se i bit corrispondenti negli operandi sono diversi.

Codice di esempio:

#include <stdio.h>

int main() {
  unsigned int num1 = 9;  // Binary representation: 1001
  unsigned int num2 = 6;  // Binary representation: 0110

  unsigned int result = num1 ^ num2;

  printf("Result: %u\n", result);  // Output: 9 (Binary: 1001)

  return 0;
}

Output:

Result: 15

In questo esempio, l’operazione XOR bit per bit (num1 ^ num2) produce 1001 in binario, che è 9 in decimale. Ciò significa che i bit corrispondenti in num1 e num2 sono diversi.

Generalmente, il confronto dei bit implica l’accesso a valori di singolo bit e l’esecuzione delle operazioni necessarie, come l’implementazione di un campo di bit utilizzando le parole chiave union e struct.

Tuttavia, le operazioni bit per bit offrono un metodo più efficiente per confrontare bit specificati nei numeri. In questo caso, implementiamo una funzione separata adatta al tipo u_int32_t, che è garantito avere una larghezza di 32 bit.

Il programma di esempio seguente accetta tre numeri interi come argomenti della riga di comando, i primi due dei quali sono i numeri che vengono confrontati, mentre il terzo numero intero specifica l’n-esimo bit. Si noti che convertiamo gli elementi argv usando strtol, perdendo così un po’ di precisione quando memorizziamo i valori restituiti nel tipo u_int32_t.

La funzione compareBits dichiara due variabili locali che memorizzano valori intermedi - mask e tmp. Impostiamo l’n-esimo bit nella mask spostando 1 a sinistra di nth - 1 posizioni.

Quindi, entrambi i numeri di input dell’utente vengono sottoposti a XOR per ottenere le differenze di bit in ciascuna posizione, con un bit impostato nel risultato che denota valori diversi. Infine, dobbiamo estrarre il bit dalla posizione n-esima e controllare se il valore è 0.

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

bool compareBits(u_int32_t n1, u_int32_t n2, u_int32_t nth) {
  u_int32_t mask, tmp;

  mask = 1 << (nth - 1);
  tmp = n1 ^ n2;

  if ((tmp & mask) == 0)
    return true;
  else
    return false;
}

int main(int argc, char *argv[]) {
  u_int32_t num1, num2, bit;

  if (argc != 4) {
    fprintf(stderr, "Usage: %s integer1 integer2 nth_bit \n", argv[0]);
    exit(EXIT_FAILURE);
  }

  num1 = strtol(argv[1], NULL, 0);
  num2 = strtol(argv[2], NULL, 0);
  bit = strtol(argv[3], NULL, 0);

  compareBits(num1, num2, bit) ? printf("bits equal!\n")
                               : printf("bits not equal!\n");

  exit(EXIT_SUCCESS);
}

Formato del file di esempio:

./main 1234 1231 1

Formato del file di input:

bits not equal!

Ad esempio, gli interi 1234 e 1231 sono rappresentati in binario come 00000000000000000000010011010010 e 00000000000000000000010011001111, rispettivamente.

Pertanto, applicando XOR a questi due si ottiene una rappresentazione binaria 00000000000000000000000000011101, alla quale viene infine applicato AND con la maschera 00000000000000000000000000000010 per estrarre il valore della posizione del singolo bit. Se il risultato è tutto zeri, implica che i bit confrontati sono uguali; altrimenti, è il contrario.

In alternativa, però, possiamo accorciare la funzione compareBits e spostare le operazioni XOR/AND nell’istruzione return, come mostrato nel seguente codice di esempio. Si noti che la funzione restituisce l’opposto logico delle operazioni XOR/AND bit per bit, poiché stampiamo i messaggi corrispondenti nella funzione chiamante utilizzando l’istruzione ternaria ? :.

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

bool compareBits(u_int32_t n1, u_int32_t n2, u_int32_t nth) {
  u_int32_t mask;

  mask = 1 << (nth - 1);

  return !((n1 ^ n2) & mask);
}

int main(int argc, char *argv[]) {
  u_int32_t num1, num2, bit;

  if (argc != 4) {
    fprintf(stderr, "Usage: %s integer1 integer2 nth_bit \n", argv[0]);
    exit(EXIT_FAILURE);
  }

  num1 = strtol(argv[1], NULL, 0);
  num2 = strtol(argv[2], NULL, 0);
  bit = strtol(argv[3], NULL, 0);

  compareBits(num1, num2, bit) ? printf("bits equal!\n")
                               : printf("bits not equal!\n");

  exit(EXIT_SUCCESS);
}

Formato del file di esempio:

./main 1234 1231 2

Formato del file di input:

bits equal!

Usare l’operatore OR (|) bit per bit per il confronto di bit in C

L’operatore OR bit per bit (|) esegue un confronto bit per bit tra i bit corrispondenti di due operandi. Il risultato di questa operazione è un nuovo valore in cui ciascun bit è impostato se almeno uno dei bit corrispondenti in uno dei due operandi è impostato.

Quando viene applicata a una coppia di bit, l’operazione OR segue questa logica:

`0 0`
`0 1`
`1 0`
`1 1`

Considerate il seguente esempio per illustrare l’operazione OR bit per bit:

#include <stdio.h>

int main() {
  unsigned int num1 = 9;  // Binary representation: 1001
  unsigned int num2 = 6;  // Binary representation: 0110

  unsigned int result = num1 | num2;

  printf("Result: %u\n", result);  // Output: 15 (Binary: 1111)

  return 0;
}

Output:

Result: 15

In questo esempio, abbiamo due interi senza segno, num1 e num2 inizializzati con i valori 9 e 6, rispettivamente. Le loro rappresentazioni binarie sono 1001 e 0110.

Quando eseguiamo l’operazione OR bit per bit (num1 | num2), il risultato è 1111 in binario, che è 15 in decimale. Ciò significa che almeno uno dei bit corrispondenti in num1 o num2 è impostato.

Usare l’operatore NOT (~) bit per bit per il confronto di bit in C

L’operatore NOT bit per bit (~) è un operatore unario, il che significa che opera su un singolo operando. Quando viene applicato a un numero binario, inverte ciascun bit, trasformando gli 0 in 1 e gli 1 in 0.

Codice di esempio:

#include <stdio.h>

int main() {
  unsigned int num = 9;  // Binary representation: 1001

  unsigned int result = ~num;

  printf(
      "Result: %u\n",
      result);  // Output: 4294967286 (Binary: 11111111111111111111111111111010)

  return 0;
}

Output:

Result: 4294967286

In questo esempio, dichiariamo una variabile intera senza segno num e la inizializziamo con il valore 9. In binario, questo è rappresentato come 1001.

Applichiamo quindi l’operatore NOT bit per bit (~num). Questo inverte tutti i bit, producendo 11111111111111111111111111111010 in binario.

Il risultato viene stampato sulla console, che è 4294967286 in decimale.

NOT bit per bit per confrontare i bit

Una delle applicazioni dell’operatore NOT bit per bit è il confronto dei bit. Invertendo i bit di una variabile, possiamo facilmente controllare se un particolare bit è impostato o meno.

Codice di esempio:

#include <stdio.h>

int main() {
  unsigned int num = 9;  // Binary representation: 1001

  // Check if the 2nd bit is set
  unsigned int mask = 1 << 1;  // Shift 1 by 1 position to the left => 0002

  unsigned int result = ~num & mask;

  if (result == mask) {
    printf("2nd bit is set.\n");
  } else {
    printf("2nd bit is not set.\n");
  }

  return 0;
}

Output:

2nd bit is set.

In questo esempio, vogliamo controllare se il secondo bit della variabile num è impostato.

Creiamo prima una maschera spostando l'1 di 1 posizione a sinistra (1 << 1), ottenendo 0002 in binario. Applichiamo quindi l’operatore NOT bit per bit a num, ottenendo 11111111111111111111111111111010 in binario.

Successivamente, eseguiamo un’operazione AND bit per bit tra il num invertito e la maschera. Questo isola il secondo bit.

Se il risultato è uguale alla maschera, significa che il secondo bit è impostato e stampiamo un messaggio corrispondente. Altrimenti, stampiamo un messaggio che indica che il secondo bit non è impostato.

Conclusione

In questa esplorazione completa degli operatori bit per bit in C, abbiamo coperto operazioni fondamentali come AND, OR e NOT. Queste operazioni sono preziose per attività che comportano la manipolazione di dati di basso livello, come la compressione dei dati, la crittografia e la programmazione di sistemi embedded.

In particolare, abbiamo approfondito l’uso dell’operatore NOT (~) bit per bit per confrontare singoli bit. Applicando l’operatore ~, possiamo facilmente invertire i bit di una variabile, permettendoci di controllare se un particolare bit è impostato o meno. Questa tecnica è essenziale in scenari in cui è richiesta una manipolazione precisa a livello di bit.

Comprendere e padroneggiare le operazioni bit per bit è cruciale per i programmatori che lavorano su attività che comportano un’interazione diretta con l’hardware o che richiedono soluzioni ottimizzate per ambienti con risorse limitate. Con le conoscenze acquisite da questo articolo, ora siete in grado di sfruttare questi potenti strumenti nei vostri progetti di programmazione in C.