Примеры использования объединений
Получение внутреннего представления вещественного числа
union bytes{
double d;
unsigned char c [sizeof (double)];
};
int main ()
{
bytes ob={199.5};
for (int j=sizeof(double)-1; j>=0; j--)
{
cout << "byte " <<j << ": ";
for (int i=128; i; i>>=1) //проход по битам
if (i & ob.c[j]) //выделение бита
cout << "1";
else cout << "0";
cout << "\n";
}
_getch();
return 0;
}
Например, внутреннее представление числа -256.5: С0 70 08 00 00 00 00 00 16
в памяти значение хранится в виде: 00 00 00 00 00 08 70 С016
Объяснение, как получено это значение, дано в разделе «Внутреннее представление вещественных чисел» лекции 8.
Использование перечислимого типа для обращения к полям объединения
int main()
{ enum paytype {CARD, CHECK}; //две формы оплаты с числовыми значениями 0, 1
paytype ptype; //определение переменной перечисляемого типа
union
{char card[25];
long check;
} info;
Возможное присваивание значения объединению:
ptype = CARD; //переменная-флаг получает значение CARD (0)
strcpy (info.card, "12345"); //объединение получает свое значение через поле card
или
ptype = paytype(1); //переменная–флаг получает значение CHECK (1)
info.check= 105l; //объединение получает свое значение через поле check
Вывод значения переменной на экран:
switch (ptype) {
case CARD: cout <<"card:" << info.card<< endl; break;
case CHECK: cout <<"check:" << info.check<< endl; break;
}
_getch();
return 0;
}
Реализуем пример по-другому.
Создадим структуру, включающую объединение и поле перечислимого типа, характеризующее форму оплаты:
int main()
{
enum paytype {CARD, CHECK}; //две формы оплаты
struct{
paytype ptype; //поле-флаг включено в состав структуры
union
{char card[25];
long check;
} info;
} str;
Возможное присваивание значения объединению:
str.ptype = paytype(0); //заполняем поле-флаг объединения, как элемента структуры
strcpy(str.info.card, "12345");//объединение, как элемент структуры,
//получает свое значение через поле card
или
str.ptype = paytype(1); //заполняем поле-флаг объединения, как элемента структуры
str.info.check= 105l; //объединение, как элемент структуры,
//получает свое значение через поле check
Вывод на экран значения объединения как элемента переменной-структуры:
switch (str.ptype) {
case CARD: cout <<"card:" << str.info.card<< endl; break;
case CHECK: cout <<"check:" << str.info.check<< endl; break;
}
_getch();
return 0;
}
Битовые поля структур и объединений
Определение битовых полей
Язык С++ допускает использование в структурах и объединениях в качестве полей данных особого типа полей – битовых. Каждое битовое поле представляет целое или беззнаковое целое значение, занимающее в памяти фиксированное число битов. Число связанных бит – ширина поля.
Общий синтаксис описания битового поля:
тип_поля [имя_поля]: ширина_поля;
Члены битовых полей могут иметь значения базовых целых типов (знаковых или беззнаковых). Эти ключевые слова записываются в поле «тип_поля». Для переносимости программ лучше указывать служебные слова signed или unsigned, однако заметим, что сама природа структур с битовыми полями не способствует переносимости.
Определение структурной переменной с битовыми полями имеет формат:
struct имя_структурного _типа {
тип_поля1 имя_поля1: ширина_поля1;
тип_поля2 имя_поля2: ширина_поля2;
} имя_структурной_переменной;
Каждому полю выделяется столько бит, сколько задается в поле «ширина». Ссылка на битовое поле выполняется по имени, указываемому в поле «имя». Например:
struct EXAMPLE {int i:3;
unsigned j:2;
int :3;
int k: 2;
} my_struct;
Это описание включает 4 битовых поля: iиз трех битов (значения от -4 до 3), j из двух битов (значения от 0 до 3), поле без имени из трех битов и поле k из двух битов (значения от -2 до 1). В памяти, отводимой под структуру EXAMPLE, битовое поле k будет расположено не непосредственно за полем j, а через три бита от него (на величину безымянного поля). Неименованное поле используется в структуре как заполнение:ничто не будет храниться в этих битах.
При ссылке на битовое поле, в выражениях выделяются (по шаблону) нужные биты и при необходимости выполняется сдвиг числа вправо. В результате оно вступает в операцию в соответствии с типом как число со знаком или без него. При ссылке на битовое поле слева от операции присваивания выполняется обратная операция: сдвиг числа влево, выделение по маске нужных битов и размещение их в структурной переменной поразрядной логической операцией с предыдущим содержимым поля.
Структуры с битовыми полями используются подобно обычным структурам. Битовые поля не могут быть самостоятельным объектом программы, а лишь элементами структур, объединений, классов. Не могут они объединяться и в массивы. К битовым полям не может быть применен оператор взятия адреса &, так как битовое поле может находиться внутри байта.
Битовые поля позволяют рационально использовать память с помощью хранения данных в минимально требуемом количестве битов, экономить память, работая с однобитовыми флажками, формировать объекты с длиной внутреннего представления, не кратной байту (т.е. упаковывать информацию). Их назначение – удобный доступ к отдельным битам, компактное представление в памяти упакованных структур. Однако в ряде случаев их использование может привести к замедлению выполнения программы.
Компилятор старается размещать битовые поля в памяти последовательно. Для выравнивания он может свободно переходить к следующему байту или слову.
Манипуляции с битовыми полями являются машинно-зависимыми. Поля могут размещаться как слева направо, так и справа налево (зависит от реализации). В некоторых компьютерах битовые поля могут пересекать границы машинного слова, тогда как в других – нет, но максимальная ширина поля не должна превышать длины слова компьютера. Размещение поля с длиной, не кратной длине слова или байта, возможно с расположением «встык», без пропусков или же с выравниванием на границе. Влиять на размещение битовых полей можно и на уровне синтаксиса языка С++ (в этом случае для выравнивания можно использовать недоступные биты – безымянные поля).
Для структуры с битовыми полями:
struct
{int a:10;
int b:14;
} xx;
представление в памяти переменной хх, в зависимости от реализации может иметь вид:
при выравнивании на границе слова или байта:
7 0 7 0 7 0 7 0
z z z z z z | z z z z z z z z | ww | wwwwwwww |
хх.b (14 битов) хх.a (10 битов)
при плотной упаковке:
7 0 7 0 7 0 7 0
z z z z z z z z | z z z z z z ww | wwwwwwww |
хх.b (14 битов) хх.a (10 битов)