Bitfield (C++)

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită la 6 octombrie 2014; controalele necesită 48 de modificări .

Câmp de biți ( câmp de biți ing.  ) în programare  - un număr de biți aranjați secvențial în memorie , a căror valoare procesorul nu este capabil să o citească din cauza particularităților implementării hardware .

Despre implementările hardware

Dacă este necesar să citiți valoarea scrisă în locația de memorie , procesorul efectuează următoarele acțiuni:

Valoarea citită este egală cu valoarea din locația de memorie specificată și are o dimensiune egală cu lățimea magistralei de date ( dimensiunea cuvântului mașinii ).

Lățimea magistralei de adrese determină dimensiunea minimă a memoriei adresabile . Controlerul de memorie necesită ca adresa celulei să fie aliniată la granița unui cuvânt de mașină .

Dacă lățimea de biți (numărul de biți) a valorii de citit (a unui câmp de biți) nu este egală cu dimensiunea cuvântului de mașină , după citirea cuvântului de mașină din memorie , trebuie executate instrucțiuni suplimentare :

Exemplu. Lăsa:

0011 0100 1010 11 10 01 00 0111 0100 1100 2
  1. Procesorul va citi din memorie un cuvânt mașină egal cu valoarea inițială:
0011 0100 1010 11 10 01 00 0111 0100 1100 2
  1. Instrucțiunea va seta biții care and nu se află în câmpul de biți la 0. Rezultat:
0000 0000 0000 00 10 01 00 0000 0000 0000 2
  1. Instrucțiunea va muta biții câmpului de biți de la stânga la dreapta, astfel încât bitul cel mai puțin semnificativ al câmpului de biți devine bitul cel mai puțin semnificativ al cuvântului mașină . Rezultat:shr
0000 0000 0000 0000 0000 0000 0000 1001 2

Dacă adresa valorii care urmează să fie citită din memorie nu este aliniată la granița unui cuvânt de mașină , sunt necesari pași suplimentari:

Exemplu. Lăsa:

0011 0100 1010 1110 0100 011 1 0100 1100 2 0011 01 00 1010 1110 0100 0111 0100 1100 2
  1. Procesorul va citi din memorie două cuvinte mașină care conțin biții doriti; valorile sunt egale cu originalul:
0011 0100 1010 1110 0100 011 1 0100 1100 2 0011 01 00 1010 1110 0100 0111 0100 1100 2
  1. Cu ajutorul a două instrucțiuni and , biții care nu sunt incluși în câmpul de biți vor fi scriși cu valorile 0. Rezultat:
0000 0000 0000 0000 0000 000 1 0100 1100 2 0011 01 00 0000 0000 0000 0000 0000 0000 2
  1. Cu ajutorul instrucțiunii, shr biții celui de-al doilea cuvânt mașină vor fi mutați de la stânga la dreapta, astfel încât bitul cel mai puțin semnificativ al câmpului de biți să devină bitul cel mai puțin semnificativ al cuvântului mașină . Cu ajutorul instrucțiunii, shl biții primului cuvânt mașină vor fi deplasați de la dreapta la stânga, astfel încât biții mai puțin semnificativi să fie eliberați pentru biții celui de-al doilea cuvânt mașină (pentru pasul următor). Rezultat:
0000 0000 0000 0000 0 101 0011 00 00 0000 2 0000 0000 0000 0000 0000 0000 00 00 1101 2
  1. Cu ajutorul unei instrucțiuni, or biții a două cuvinte mașină vor fi „suprapuși” unul peste altul. Rezultat:
0000 0000 0000 0000 0 101 0011 0000 1101 2

Se pot efectua pașii suplimentari descriși:

Dezavantaj: comenzile suplimentare încetinesc execuția programului . Avantaj: atunci când se utilizează câmpuri de biți, se obține cea mai densă împachetare a informațiilor .

Despre compilatoare

În general, compilatoarele permit numai următoarele operații pe câmpuri de biți:

Câmpul de biți în sine este tratat de compilator ca un număr fără semn . Ordinea câmpurilor de biți în structura datelor depinde de platforma hardware și de implementarea compilatorului : unii compilatori plasează câmpurile de biți pornind de la biții mai puțin semnificativi, în timp ce alții le plasează de la cei mai semnificativi.

Aplicație

Câmpurile de biți sunt folosite pentru cel mai complet pachet de informații , dacă viteza de acces la aceste informații nu este importantă. De exemplu, pentru a crește lățimea de bandă a canalului atunci când se transmite informații prin rețea sau pentru a reduce dimensiunea informațiilor în timpul stocării. De asemenea, utilizarea câmpurilor de biți este justificată dacă procesorul acceptă instrucțiuni specializate pentru lucrul cu câmpuri de biți, iar compilatorul utilizează aceste instrucțiuni atunci când generează codul mașinii .

De exemplu, pe mașinile cu un cuvânt de 32 de biți , toate câmpurile dintr-un pachet IPv4 (cu excepția câmpurilor „adresa expeditorului” și „adresa de destinație”) vor fi câmpuri de biți, deoarece dimensiunea lor nu este de 32 de biți și adresele lor nu sunt un multiplu de 4 octeți . Dacă, în plus, procesorul acceptă citirea și scrierea directă a numerelor de 8 și 16 biți, singurele câmpuri de biți vor fi versiunea, dimensiunea antetului, DSCP , ECN , steagurile și decalajul fragmentului.

Operații pe câmpuri multibiți

Să fie câmpuri de patru biți într-un octet:

Număr de biți 7 [*1] 6 5 patru 3 2 unu 0 [*2]
câmp de biți d c b A
  1. Al 7-lea bit este cel mai semnificativ bit.
  2. Al 0-lea bit este bitul cel mai puțin semnificativ.

Valoarea unui număr de opt biți x , compus din câmpurile de biți a , b , c și d , poate fi calculată folosind formula: (1) .

Dacă a=1 , b=0 , c=2=10 2 și d=5=0101 2 , x va fi .

Asamblarea unui singur număr din câmpurile de biți

Dacă procesorul funcționează cu numere binare , formula (1) poate fi optimizată . După înlocuirea operațiilor „ exponentiare ” cu „ deplasare logică ”, „ adăugare ” cu „ bit SAU ”, formula (1) va lua forma:

x = ( d << 4 ) | ( c << 2 ) | ( b << 1 ) | A

Deplasarea logică a unui număr binar este echivalentă cu înmulțirea/împărțirea cu un multiplu al unei puteri de doi: 2 1 =2, 2 2 =4, 2 3 =8 etc.

Extragerea unui câmp de biți

Există două moduri de a obține valoarea v a unui câmp de biți al numărului x :

  • v = ( x & mask_1 ) >> offset;
  • v = ( x >> offset ) & mask_2.

Prima metodă efectuează mai întâi o operație AND pe biți , apoi o deplasare logică la dreapta. În a doua metodă, operațiile sunt efectuate în ordine inversă. Masca constantă_2 poate fi obținută din masca constantă_1 : . offset  este numărul primului bit cel mai puțin semnificativ al câmpului de biți v , exponentul din formula (1) .
mask_2 = mask_1 >> offset

Pentru a obține valoarea unui câmp de biți din numărul x în primul mod, se efectuează trei operații:

  1. calculați „masca de biți” mask_1  - un număr care are unități în biții corespunzători câmpului de biți și zerouri în biții rămași;
Număr de biți 7 6 5 patru 3 2 unu 0
masca pentru a 0 0 0 0 0 0 0 unu
masca pentru b 0 0 0 0 0 0 unu 0
masca pentru c 0 0 0 0 unu unu 0 0
masca pentru d unu unu unu unu 0 0 0 0
  1. înmulțiți „bitmask” cu numărul utilizând operația „ bit AND ”;
  2. efectuează o deplasare logică la dreapta cu biți offset .
câmp de biți decalaj
A 0
b unu
c 2
d patru

Un exemplu de obținere a unei valori dintr-un câmp de biți c :

c = ( x & 00001100 b ) >> 2

Cu a doua metodă:

  1. efectuați o deplasare logică la dreapta;
  2. calculați „masca de biți” mask_2  - un număr în care primele n cifre cele mai puțin semnificative sunt setate la unu, iar cifrele rămase sunt zerouri; n  este numărul de cifre ale câmpului de biți;
Număr de biți 7 6 5 patru 3 2 unu 0
masca pentru a 0 0 0 0 0 0 0 unu
masca pentru b 0 0 0 0 0 0 0 unu
masca pentru c 0 0 0 0 0 0 unu unu
masca pentru d 0 0 0 0 unu unu unu unu
  1. înmulțiți „bitmask” cu numărul utilizând operația „ bit AND ”.

Un exemplu de obținere a unei valori dintr-un câmp de biți c :

c = ( x >> 2 ) & 00000011 b

Câmpul de biți cel mai puțin semnificativ (câmpul a în acest exemplu) nu este deplasat logic cu zero biți. Exemplu:
a = ( x & 00000001b ) >> 0
a = ( x >> 0 ) & 00000001b )

a = x și 00000001 b

În a doua metodă, câmpul cel mai înalt (câmpul d din acest exemplu) nu efectuează înmulțirea logică, deoarece operația logică de deplasare la dreapta adaugă zero biți la număr. Exemplu:
d = ( x >> 4 ) & 00001111b )

d = x >> 4

Înlocuire bitfield

Pentru a înlocui un câmp de biți, sunt efectuate trei operații:

  1. se calculează o mască - un număr ai cărui biți corespunzători câmpului de biți au zerouri;
  2. operatia " bit AND " inmulteste numarul x cu masca; operația realizează setarea zerourilor în biții corespunzători măștii;
  3. operația „ bit inclusiv SAU ” este utilizată pentru a adăuga produsul rezultat și numărul x deplasat cu numărul de biți corespunzător decalajului câmpului de biți de la începutul cuvântului.

Un exemplu de înlocuire a unei valori pentru un câmp de biți d :

xnew = ( x & 00001111 b ) | ( d << 4 )

Operații pe câmpuri de un bit

Există metode mai simple de lucru cu câmpuri de biți care au un bit lățime.

Câmpurile de biți a și b ocupă câte un bit.

Verificarea unui singur bit

Pentru a obține valoarea unui singur bit, se realizează o multiplicare logică (operație „ bit AND ”) a numărului x printr-o mască care are un bit setat, corespunzător unui bit dintr-un câmp de un bit. Dacă rezultatul este 0, bitul este 0.

Un exemplu de obținere a valorii unui câmp de un bit b :

b = ( ( x & 00000010 b ) != 0 )

Pentru a verifica dacă unul sau mai mulți biți din grup sunt egali cu unul, se ia o mască, în care unitățile sunt setate în pozițiile biților bifați:

a_sau_b = ( ( x & 00000011 b ) != 0 )

Pentru a verifica dacă toți biții din grup sunt egali cu unul, utilizați „ ȘI pe biți ” și operația „ == ” :

a_and_b = ( ( x & 00000011 b ) == 00000011 b )

Setarea bătăilor

Pentru a seta biții, se efectuează o adăugare logică (operația „ bit SAU ”) a numărului x cu o mască care îi are setați în pozițiile corespunzătoare câmpului de biți.

Un exemplu de setare a unui pic dintr-un câmp de un bit a :

x1 = x | 00000001b _

Pentru a seta mai mulți biți ai numărului x , de exemplu, biții câmpurilor de un bit a și b , utilizați o mască care are biți corespunzători biților câmpurilor de biți setate la uni:

x2 = x | 00000011b _

Eliminarea bătăilor

Pentru a seta unul sau mai mulți biți de zerouri, numărul x este înmulțit cu operația „ bit AND ” de către mască, în care biții zero sunt setați în pozițiile corespunzătoare câmpului de biți.

Un exemplu de setare a biților la zero în câmpul de biți b :

x3 = x & 11111101 b

Beat Switching

Pentru a schimba valoarea biților la opus (de la 0 la 1 și de la 1 la 0), numărul x se adaugă prin operația „ SAU exclusiv de biți ” cu o mască în care unitățile sunt setate în poziții corespunzătoare pozițiilor de biții de comutare.

Un exemplu de modificare a valorilor biților din câmpul de biți b :

x4 = x ^ 00000010b _

Operații pe câmpuri semnate în complement a doi

În memoria computerului, numerele întregi negative pot fi codificate în unul dintre următoarele moduri:

Majoritatea procesoarelor moderne implementează a treia metodă. Luați în considerare reprezentarea binară a mai multor numere întregi în complement a doi :

4 = 00000100 2 3 = 00000011 2 2 = 00000010 2 1 = 00000001 2 0 = 00000000 2 -1 = 11111111 2 -2 = 11111112 = 11111112 = 10111112 = 10111110111111111101 etc.

Fie că câmpurile c și d au formatul „ cod complementar ”. Atunci câmpul c poate stoca numere de la −2=10 2 la 1=01 2 , iar câmpul d poate stoca numere de la  −8=1000 2 la 7=0111 2 .

Asamblarea și înlocuirea numerelor

Fiecare dintre termeni (cu excepția celui mai înalt), pentru a nu strica biții mai mari, trebuie înmulțit cu o mască de biți de lungimea corespunzătoare. În special:

x = (d << 4) + ((c & 00000011b) << 2) + (b << 1) + a

Extragerea numerelor

Pentru a extrage numere, trebuie să mutați câmpul cu numărul necesar de biți la dreapta, înmulțind în același timp bitul de semn. De exemplu, puteți utiliza schimbarea aritmetică pentru a face acest lucru . Dacă x are 8 biți lungime, atunci

c = (x << 4 ) >>a 6 d = x >>a 4

Atenţie! În limbajul de programare Java , opusul este adevărat: semnul denotă o schimbare aritmetică , iar semnul denotă  o schimbare logică . >>>>>

Dacă nu există o schimbare aritmetică, atunci...

c1 = x >> 2 dacă (c1 și 00000010b ≠ 0) atunci c = c1 | 0x11111100b în caz contrar c = c1 & 0x00000011b

Declarații Bitfield

În C și C++ , la declararea unui câmp de biți , este folosit caracterul două puncte ( :) . Coloana este urmată de o expresie constantă care determină numărul de biți din câmpul de biți [1] . Exemplu:  

struct rgb { nesemnat r : 3 ; nesemnat g : 3 ; nesemnat b : 3 ; };

Vezi și

Note

  1. Ray Lishner. C++. Referință = C++ Pe scurt / Ch. ed. E. Strogonova. - Sankt Petersburg. : Peter , 2003 . - S. 193. - 907 p. - 3500 de exemplare.  - ISBN 5-94723-928-0 , BBC 32.973-018.1ya22, UDC 681.3.06(03).