Sök…
Introduktion
Bitfält packar tätt C- och C ++ -strukturer för att minska storleken. Detta verkar smärtfritt: ange antalet bitar för medlemmar, och kompilatorn gör arbetet med att samverka bitar. Begränsningen är oförmåga att ta adressen till en bitfältmedlem, eftersom den lagras samblandad. sizeof()
tillåts inte.
Kostnaden för bitfält är långsammare, eftersom minne måste hämtas och bitvisa operationer tillämpas för att extrahera eller ändra medlemsvärden. Dessa operationer lägger också till körbar storlek.
Anmärkningar
Hur dyra är bitvisa operationer? Anta en enkel icke-bitars fältstruktur:
struct foo {
unsigned x;
unsigned y;
}
static struct foo my_var;
I någon senare kod:
my_var.y = 5;
Om sizeof (unsigned) == 4
, lagras x i början av strukturen och y lagras 4 byte i. Genererad monteringskod kan likna:
loada register1,#myvar ; get the address of the structure
storei register1[4],#0x05 ; put the value '5' at offset 4, e.g., set y=5
Detta är enkelt eftersom x inte blandas med y. Men tänk dig att omdefiniera strukturen med bitfält:
struct foo {
unsigned x : 4; /* Range 0-0x0f, or 0 through 15 */
unsigned y : 4;
}
Både x
och y
kommer att tilldelas 4 bitar, som delar en enda byte. Strukturen tar således upp 1 byte, istället för 8. Betrakta aggregatet för att ställa in y
nu, förutsatt att det hamnar i den övre nibble:
loada register1,#myvar ; get the address of the structure
loadb register2,register1[0] ; get the byte from memory
andb register2,#0x0f ; zero out y in the byte, leaving x alone
orb register2,#0x50 ; put the 5 into the 'y' portion of the byte
stb register1[0],register2 ; put the modified byte back into memory
Detta kan vara en bra avvägning om vi har tusentals eller miljoner av dessa strukturer, och det hjälper till att hålla minnet i cache eller förhindra byte - eller kan uppblåsa den körbara för att förvärra dessa problem och långsam behandling. Som med alla saker, använd god bedömning.
Användning av enhetsdrivrutin : Undvik bitfält som en smart implementeringsstrategi för enhetsdrivrutiner. Layoutlayouter för bitfält är inte nödvändigtvis konsekventa mellan kompilatorerna, vilket gör sådana implementationer icke bärbara. Läs-ändra-skriva för att ställa in värden kanske inte gör vad enheter förväntar sig, vilket orsakar oväntat beteende.
Förklaring och användning
struct FileAttributes
{
unsigned int ReadOnly: 1;
unsigned int Hidden: 1;
};
Här kommer varje av dessa två fält att uppta en bit i minnet. Det anges av : 1
uttryck efter variabelnamnen. Bastyp för bitfält kan vara vilken som helst integrerad typ (8-bitars int till 64-bitars int). Att använda unsigned
typ rekommenderas, annars kan överraskningar komma.
Om fler bitar krävs, byt ut "1" med antalet nödvändiga bitar. Till exempel:
struct Date
{
unsigned int Year : 13; // 2^13 = 8192, enough for "year" representation for long time
unsigned int Month: 4; // 2^4 = 16, enough to represent 1-12 month values.
unsigned int Day: 5; // 32
};
Hela strukturen använder bara 22 bitar, och med normala kompilatorinställningar skulle sizeof
denna struktur vara 4 byte.
Användningen är ganska enkel. Förklara bara variabeln och använd den som vanlig struktur.
Date d;
d.Year = 2016;
d.Month = 7;
d.Day = 22;
std::cout << "Year:" << d.Year << std::endl <<
"Month:" << d.Month << std::endl <<
"Day:" << d.Day << std::endl;