Operatori pe biți (& | ^ ~ << >>) în C

Operatori C89

Lucrează direct cu biții unui întreg: steaguri (flags), măști, deplasări; folosiți la permisiuni, protocoale și hardware.

Sintaxă
a & b    // ȘI pe biți
a | b    // SAU
a ^ b    // SAU exclusiv
~a       // inversare
a << n   // deplasare la stânga
a >> n   // deplasare la dreapta

Ce face Operatori pe biți (& | ^ ~ << >>)

Operatorii pe biți compară bit cu bit două numere întregi. & păstrează biții care sunt 1 în ambele, | pe cei care sunt 1 în oricare, ^ pe cei diferiți, iar ~ inversează toți biții.

a << n mută biții lui a cu n poziții la stânga (înmulțire cu 2n), a >> n la dreapta (împărțire cu 2n pentru numere pozitive). Pentru deplasări, folosește tipuri fără semn: deplasarea unui număr negativ la stânga este comportament nedefinit.

Un caz tipic sunt steagurile: fiecare bit înseamnă o opțiune (citire, scriere, execuție). Setezi un bit cu |=, îl ștergi cu &= ~, îl verifici cu & și îl comuți cu ^=.

Exemple

Exemplul 1: Permisiuni ca steaguri

Fiecare permisiune are un bit propriu. 0x în %#x afișează valoarea în hexazecimal.

#include <stdio.h>

enum { CITIRE = 1u << 0, SCRIERE = 1u << 1, EXECUTIE = 1u << 2 };

int main(void) {
    unsigned drepturi = CITIRE | SCRIERE;
    printf("drepturi = %#x\n", drepturi);
    printf("poate scrie: %s\n", (drepturi & SCRIERE) ? "da" : "nu");
    printf("poate executa: %s\n", (drepturi & EXECUTIE) ? "da" : "nu");

    drepturi &= ~SCRIERE;      // șterge dreptul de scriere
    drepturi |= EXECUTIE;      // adaugă execuția
    printf("după modificări = %#x\n", drepturi);
    return 0;
}

Rezultat

drepturi = 0x3
poate scrie: da
poate executa: nu
după modificări = 0x5

Exemplul 2: Afișarea biților unui număr

Funcția testează fiecare bit, de la cel mai semnificativ, cu o mască 1u << i.

#include <stdio.h>

void biti(unsigned char x) {
    for (int i = 7; i >= 0; i--) {
        putchar((x & (1u << i)) ? '1' : '0');
    }
    putchar('\n');
}

int main(void) {
    unsigned char a = 0x5A, b = 0x0F;
    printf("a     = "); biti(a);
    printf("b     = "); biti(b);
    printf("a & b = "); biti(a & b);
    printf("a | b = "); biti(a | b);
    printf("a ^ b = "); biti(a ^ b);
    printf("~a    = "); biti((unsigned char)~a);
    return 0;
}

Rezultat

a     = 01011010
b     = 00001111
a & b = 00001010
a | b = 01011111
a ^ b = 01010101
~a    = 10100101

Exemplul 3: Deplasări: înmulțire și împărțire cu puteri ale lui 2

#include <stdio.h>

int main(void) {
    unsigned x = 5;
    printf("5 << 3 = %u\n", x << 3);
    printf("40 >> 2 = %u\n", 40u >> 2);
    unsigned culoare = 0xFF8800;           // RGB
    printf("roșu=%u verde=%u albastru=%u\n",
           (culoare >> 16) & 0xFF, (culoare >> 8) & 0xFF, culoare & 0xFF);
    return 0;
}

Rezultat

5 << 3 = 40
40 >> 2 = 10
roșu=255 verde=136 albastru=0

Greșeli frecvente

  • Scrii if (x & MASCA == MASCA). == are prioritate mai mare decât &; pune paranteze: if ((x & MASCA) == MASCA).
  • Deplasezi cu un număr de poziții mai mare sau egal cu lățimea tipului (1u << 32 pe un unsigned de 32 de biți). Este comportament nedefinit.
  • Folosești ^ ca ridicare la putere. În C, 2 ^ 3 este 1 (SAU exclusiv); pentru putere folosește pow sau înmulțiri.

Comenzi înrudite

  • Operatori de comparație și logici (== && || ! ?:): Compară valori și combină condiții: rezultatul este 1 (adevărat) sau 0 (fals); && și || se opresc cât mai devreme.
  • stdint.h și limits.h: Tipuri întregi cu dimensiune exactă (int32_t, uint8_t) și constantele cu valorile minime și maxime ale tipurilor (INT_MAX).
  • enum: Definește un set de constante întregi cu nume, de exemplu zilele săptămânii sau stările unei comenzi.
  • Operatori aritmetici (+ - * / % ++ --): Adunare, scădere, înmulțire, împărțire, restul împărțirii, atribuiri compuse și incrementare cu ++ / –.