- •Структура как пользовательский тип и совокупность данных
- •Определение шаблона структуры и структурной переменной
- •Расположение структурных переменных в памяти
- •Инициализация структурных переменных
- •Вложенные структуры
- •Операции над структурными переменными
- •Массив структур
- •Структура в качестве аргумента функции
- •Примеры работы со структурами
- •person_list
- •Объединение как пользовательский тип и совокупность данных
- •Определение объединения и переменной объединяющего типа
- •Использование перечисляемого типа для обращения к полям объединения
- •Битовые поля структур и объединений
- •Определение битовых полей
- •Формирование кода символа с помощью битовых полей объединения
- •Формирование байта и вывод на экран его двоичного представления
for (i=0; md->d > dofm[v][i]; i++) |
//пересчет порядкового значения дня года |
md->d -=dofm[v][i]; |
//в день месяца |
md->m=i; |
//присваивание значения месяцу |
}
Объединение как пользовательский тип и совокупность данных
Определение объединения и переменной объединяющего типа
Объединения находятся в близком родстве со структурами. Объединением будем называть переменную, созданную, как и в случае структур, по шаблону. Определяются объединения (шаблоны объединения, объединяющие типы) с помощью служебного слова union. Объединения, подобно структурам, содержат поля различных типов, но только размещаются эти поля в одно и то же место памяти (начинаются с одной границы). Основное назначение объединения – обеспечить возможность доступа к одному и тому же участку памяти с помощью объектов разных типов.
Определим переменную UNI объединяющего типа с помощью анонимного шаблона: union {
long L; unsigned i1; int i2;
char c[4];
} UNI;
Схема размещения переменной UNI в памяти: long L
unsigned i1 int i2
char c[4]
т.е. элементы располагаются с одного адреса. Это подтвердит и выполнение следующих операторов:
cout << &UNI.L; //все переменные имеют один и тот же адрес cout << &UNI.i1;
cout << &UNI.i2; cout << &UNI.c;
Размер памяти, выделяемый объединению, равен максимальному из размеров памяти, выделяемых для отдельных полей шаблона. Тип поля может быть любым, в том числе и структурой. Структуры могут быть членами объединения, и объединение может быть членом структуры. Разрешается создание и массива объединений.
Переменные типа объединение могут быть формальными параметрами и аргументами вызова функций. Чтобы функция не изменила аргумент-объединение при передаче по указателю или ссылке, соответствующий параметр объявляется со спецификатором const. Функция может возвращать переменную-указатель или ссылку типа объединение.
Доступ к полям объединения выполняется, аналогично структурам, через уточненное
имя:
имя_объединения.имя_поля
Программирование – лекция 18 (лекции Стрикелевой Л.В.)
15
(*указатель_на_объединение).имя_поля указатель_на_объединение->имя_поля
ссылка_на_объединение.имя_поля
Внимание!!! Члены-данные анонимного объединения можно использовать как переменные (если их имена уникальны в контексте объявления). Например:
enum |
week {sun, mon, tues, weds, thurs, fri, sat}; |
|
union { |
// анонимное объединение |
|
|
int i; |
|
}; |
week w; |
|
|
|
|
i = 6; |
if ((w == sun) || (w == sat)) |
cout << “Это выходные дни!”; |
Объединения могут быть опасны, так как их реализация часто зависит от системы.
Если бы элементы объединения имели одинаковую длину и одинаковый тип, а отличались только именами, то использование объединения было бы подобно применению ссылок: один участок памяти имел бы несколько различных имен.
Заносить значения в участок памяти, выделенный для объединения, можно с помощью любого из элементов:
union {
int ival; float fval; char cval[4];
} uval;
Переменной uval можно присваивать любой из трех типов; какой тип в данный момент находится в переменной – должен помнить программист.
Но:
инициализироваться объединение может только первым описанным полем.
Инициализатор объединения – значение для его первого члена, заключенное в фигурные скобки. Например:
union int_flt { |
|
|
|
int i; |
|
|
float x; |
|
} n = {0}; |
// член (поле) i инициализируется нулем. |
|
n.i = 7; |
|
//в объединение записано целое значение |
cout << n.i |
<< endl; |
// объединение интерпретируется как имеющее целый тип |
n.x = 7.0; |
|
// в объединение записано вещественное значение |
cout << n.x |
<< endl; |
//объединение интерпретируется как имеющее вещественный тип |
Основное достоинство объединений – возможность разных трактовок одного и того же содержимого памяти.
Пусть имеем объединение: union
{float f; unsigned long k;
Программирование – лекция 18 (лекции Стрикелевой Л.В.)
16
} FK; |
|
|
Можно присвоить объединению |
вещественное |
значение FK.f = -256.5, а |
рассматривать его затем как беззнаковое целое: |
|
|
cout << hex << FK.k; |
//получим с3804000 16. |
Если же включить в шаблон объединения массив: union
{double f; char h[8];
}FLH;
ивыполнить присваивание вещественного значения переменной FLH присваиванием этого значения полю FLH.f, то имеем возможность доступа к отдельным байтам
внутреннего представления этого значения с помощью имен FLH.h[0], FLH.h[1], и т.д.
Примеры использования объединений Получение внутреннего представления вещественного числа
union bits{
double d;
unsigned char c [sizeof (double)];
};
int main ()
{
bits ob={199.5};
for (int j=sizeof(double)-1; j>=0; j--)
{
cout << "byte " <<j << ": |
"; |
|
for (int i=128; i; i>>=1) |
cout << "1"; |
|
if (i & ob.c[j]) |
|
|
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 |
Объяснение, как получено это значение, дано в разделе «Внутреннее представление вещественных чисел» лекции 7.
Использование перечисляемого типа для обращения к полям объединения
int main()
{ enum paytype {CARD, CHECK}; //две формы оплаты с числовыми значениями 0, 1 paytype ptype; //определение переменной перечисляемого типа union
{char card[25]; long check;
} info;
Программирование – лекция 18 (лекции Стрикелевой Л.В.)
17
Возможное присваивание значения объединению:
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;
}
Программирование – лекция 18 (лекции Стрикелевой Л.В.)
18