6. Полета от битове.
В езика C и C++ е възможно да се дефинират като елементи на структура и да се използват набори от битове;
синтаксис:
[ тип [име]]:ширина;
за всяко поле се отделят точно толкова битове, колкото са указани с ширината; достъпът до битовото поле става с помощта на указаното в него име; ако името е пропуснато, то описаните битове се заделят, но достъпът до тях е невъзможен; в стандарта на C и C++ няма специални ограничения относно типа на полето и размера, тези въпроси са решени отделно за всеки компилатор; битовите полета са машинно зависима конструкция; най-често използваните типове са unsigned int и int; в Borland C и C++ може да се използва и char, но float не може да се използва;
размерът на всяко поле не може да надвишава броя на битовете, които се отделят за съответния тип;
при дефиниране на променлива от тип битово поле, заделената памет зависи от общата дължина на дефинираните полета; памет се заделя на порции, размера на които зависи от реализацията на компилатора – 1, 2, 4, 8 байта;
в Borland C и C++ тези порции зависят от характеристиката Structure Alignment; редът на разполагане на полетата в заделената за тях памет също зависи от реализацията – в Borland C и C++ полетата се разполагат от младши към старши битове, но в други реализации разполагането е от старши към младши битове;
ако структурата съдържа няколко битови полета, те започват да се разполагат в една и съща порция памет последователно в реда на появяването им;
ако за някое битово поле няма достатъчно място в текущата порция памет, то се записва в началото на следващата порция, при това в предишната порция могат да останат неизползвани битове;
при някои реализации (например Borland C и C++) битовите полета могат да пресичат границите на порциите памет;
ако две битови полета в тялото на структурата са разделени от описанието на друг елемент, който не е битово поле, тогава те ще се запишат в различни порции памет;
обръщението към битовите полета и използването им в изрази е както при обикновените полета на структурата, т.е. използват се операции ‘.’, ‘->’; ако на битово поле се присвои величина, която е по-голяма отколкото може да се запише в него, в полето се записват толкова битове, колкото е неговата ширина; при това се губят старшите битове на величината;
можем да дефинираме битово поле без име с цел да се извърши отместване в съответната порция памет; ако размерът на полето без име е 0, то непосредствено следващото битово поле се разполага в началото на следващата порция памет;
пример:
struct bfield
{ unsigned fd1:1;
:0;
int fd2:3;
} bf;
ако подравняването е по байт, тогава имаме следната конфигурация:
| | | | | | | | |x| | | | | |x|x|x|
в първия байт се записва полето fd1 (например от младши към старши битове), полето с ширина 0 указва, че другото битово поле fd2 ще се запише в началото на следващия байт;
ако вместо :0; имаме float x; и трите полета ще се запишат в различни порции памет;
примерна програма:
#include
void main ()
{ struct example
{ int i:2;
unsigned j:2;
int :2;
int k:2;
int d:8;
} mystruct;
mystruct.d = 0;
mystruct.i = 1;
mystruct.j = 3;
mystruct.k = -1;
printf (“Стойността на полетата: %d%u%d\n”, mystruct.i, mystruct.j,
mystruct.k);
}
ако подравняването е по дума имаме следната конфигурация:
|d|d|d|d|d|d|d|d|k|k| | |j|j|i|i|
при полетата signed, най-старшия бит се приема като знаков и затова в битовете за k ще се запише |1|1| и ще се интерпретира като –1;
използването на битови полета е свързано със следните ограничения:
-
не се допускат указатели към битови полета, т.е. към тях не може да се приложи операция &;
-
елементите на масив не могат да бъдат битови полета
7. Обединения.
В езика C и C++ е предвидена възможност за описания на област от паметта, в която могат да се записват в различно време променливи от различен тип; описания от този тип се наричат обединения;
синтаксис:
union име_на_тип
{ описание_на_елемент1;
описание_на_елемент2;
...
описание_на_елементn;
};
всички правила за дефиниране и работа със структури са в сила и за обединения;
съществената разлика между структурите и обединенията е, че за променливите от тип обединение компилаторът разпределя памет, достатъчна за записването на полето с максимална дължина; това е така, защото полетата на обединението започват от една и съща граница; в така разпределената памет за обединението в даден момент може да се записва само един от елементите на обединението;
пример:
union set
{ int k; //2 байта
float f; //4 байта
char ch;//1 байт
char string[5];//5 байта
} example;
дължината на това обединение зависи от подравняването на данните – ако е по байт е 5 байта, по дума 6 байта и т.н.
можем да дефинираме променливи и указатели към променливи от тип обединение по следния начин:
union set x, *p = &x; //в C++ ключовата дума union не е задължителна;
обръщението към елементите на обединението става с операциите
‘.’ и ‘->’; например:
x.k = 2;
x.f = 7.8; //по този начин губим горната стойност 2
x.ch = ‘A’; //по този начин губим горната стойност 7.8
с указателна операция:
p->k = 2;
p->f = 7.8;
x->ch = ‘A’;
кой елемент от обединението фактически е записан в паметта се контролира единствено от програмиста; например в практиката се въвежда допълнитела променлива от цял тип, която да подскаже на програмиста стойност за кое поле е записана в паметта за обединението;
повечето компилатори (Borland C и C++) поддържат структури с елементи обединения, обединения с елементи структури, масив чийто елементи са обединения – по този начин можем да избегнем ограничението елементите на масива да са от един и същи тип;
например:
union first
{ int k;
float f;
char ch;
} masiv[10];
обединението позволява по различен начин да се обръщаме към една и съща област от паметта; друг случай за използване на обединение – по-особено преобразуване на данните;
x.f = 7.8; искаме да видим какво е записано в третия байт на обединението – използваме масива string, по-точно string[3];
в Borland C и C++ обединение може да се инициализира, но само по първия елемент;
например:
union set x = { 5};//първия елемент на обединението set е int k;
Сподели с приятели: |