Структуры. Объединения. Поля битов в структурах 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Структуры. Объединения. Поля битов в структурах



Лекция 18

Структуры. Объединения. Поля битов в структурах

Структура как пользовательский тип и совокупность данных. 1

Определение шаблона структуры и структурной переменной. 1

Расположение структурных переменных в памяти. 5

Инициализация структурных переменных. 7

Вложенные структуры.. 7

Операции над структурными переменными. 8

Массив структур. 10

Структура в качестве аргумента функции. 11

Примеры работы со структурами. 12

Объединение как пользовательский тип и совокупность данных. 15

Определение объединения и переменной объединяющего типа. 15

Примеры использования объединений. 17

Получение внутреннего представления вещественного числа. 17

Использование перечисляемого типа для обращения к полям объединения. 17

Битовые поля структур и объединений. 19

Определение битовых полей. 19

Примеры использования битовых полей. 20

Вывод значений битовых полей. 20

Формирование кода символа с помощью битовых полей объединения. 21

Формирование байта и вывод на экран его двоичного представления. 22

Структура как пользовательский тип и совокупность данных

Доступ к полям структурной переменной возможен в виде:

имя_структуры. имя_элемента_структуры
                                                    //. – есть операция доступа к элементу (члену) структуры

имя_ссылки_на_структуру. имя_элемента_структуры

(*имя_указателя_на_структуру). имя_элемента_структуры

В последнем случае скобки обязательны, так как операция разыменования (*) должна относится только к указателю, а не к элементу структуры.

 

Для доступа к полям структурной переменной через указатель:
         (* имя_указателя_на_структуру ). имя_элемента_структуры

используется также операция ->:

         имя_указателя_на_структуру -> имя_элемента_структуры

                             // -> – есть операция непрямого доступа к элементу (члену) структуры

 

В случае шаблона структуры:

    struct date{

               int day;

               int mes;

               int year;

               char mon_name[10];

} x,  y, *ptr_date= &x;

 

эквивалентны записи:

(*ptr_date). year                  и         ptr_date->year

(*ptr_date).mon_name[0] и      ptr_date->mon_name[0]

 

Инициализация структурных переменных

Разрешается выполнять инициализацию полей структурной переменной при её определении. Например:

 

struct Book {char name[20];          //определение шаблона структуры

       char title[44];

       int year;

       float price;

};

 

Book              // инициализация структурных переменных при их определении

  first_book = {"Mitchel M.",

             "Unesennie vetrom",

             2007,

              20000 },

child_book = {"Troepolskij G.",

"Belij Bim Chernoe Ucho",

2006,

10000 },

dog_book = {…..};

 

 

Инициализирующие значения располагаются в порядке объявления полей в структурном типе. Типы инициализирующих значений должны быть совместимы с типами соответствующих полей в определении структурного типа.

 

Вложенные структуры

Поле, являющееся структурой, называют вложенной структурой. Естественно, что шаблон вкладываемой структуры должен быть уже известен компилятору. Например:

struct UDC { char class, subclass; int number; };

struct Book     { struct UDC udc_class;

                  char name [20];

                  char title[44];

                  int year;

                  float price;

  } first_book, child_book, dog_book;

 

Ссылка на поле вложенной структуры формируется из имени структурной переменной, имени структурного поля и имени вложенной структуры. Перечисленные имена разделяются символом «точка». Например:

first_ book. udc_ class. class = ‘A’; // ( first_book. udc_class ). class.

dog_book. udc_class. number = 681;

child_ book. udc_ class. class = 65;    //объяснить, почему верно

 

Теоретически не существует ограничения на величину уровня вложенности структур.

 

Пусть имеем вложенные структуры:

struct Distance           //длина в километрах и метрах

        { int km, m;

};

struct Pole          //размеры прямоугольного поля

       { Distance length;

         Distance width,

};

 

Тогда инициализация структурной переменной типа Pole  выглядит так:

Pole pole = { { 2, 20 }, { 1, 5 }};

 

Массив структур

Определим шаблон структуры data, содержащий информацию о дне рождения (год, месяц, день), и структурные переменные  masha_data и sasha_data с информацией о днях рождения Маши и Саши:

struct data

         {

          int year;          //год

         unsigned mes; //месяц

          unsigned day;  //день

     };

data masha_data, sasha_data;

 

Тогда:

masha_data. day  //доступ к полю «день рождения» Маши

sasha_data. year   //доступ к полю «год рождения» Саши

 

    masha_data (вся информация о дате рождения Маши),

    sasha_data   (вся информация о дате рождения Саши).

Для данного структурного типа опишем массив структур person_data:

    data person_data [20];

  Тогда:

person_data – информация о датах рождения всей группы (массива людей из двадцати человек);

person_data[i] – информация о дате рождения (i+1) – го члена группы (i – ый элемент массива);

person_data[i]. mes – месяц рождения (i+1) – го члена группы;

Определим структурный тип (шаблон структуры) mash с информацией о владельце автомобиля: номер, марка автомобиля, фамилия и адрес владельца.

struct Auto

                     {int nomer;   //номер автомобиля

                     char marka[20]; //марка автомобиля

                     char fio[40]; //фамилия владельца

                     char adres[60] //адрес владельца

};

Auto mers, volvo, alfa_r [5], *mazda,person_list [20]; // определение структурных переменных

mers. marka    –доступ к полю «марка» автомобиля mers

mers                  –   вся информация о владельце автомобиля mers

volvo. fio[0]          первая буква фамилии владельца автомобиля volvo

alfa_ r [1]. adres[0] – первый символ адреса второго элемента массива владельцев alfa _ r

person_ list – информация о всех владельцах автомобилей (массив из двадцати наборов данных);

person_ list[ i] – информация о владельце (i+1) –го автомобиля (i –ый элемент в наборе данных);

person_ list[ i]. fio – фамилия  владельца (i+1) –го автомобиля;

person_ list[ i]. fio[ j] –j-ая буква в фамилии владельца (i+1) –го автомобиля

Расположение массива структур в памяти:

person_list

1-ый владелец: person_ list [0] 2-ой владелец: person_list [1] i-ый владелец: person_list [i-1] ... 20-ый владелец: person_list [ 19]
nomer(4 байта) marka(20 байт) fio(40 байт) adres(60 байт)   nomer marka Adres Adre s adres     nomer marka fio  О adres   ОООООООО ОООООООО ОOОООООО ОООООООО ОООООООО

person_list [1]. fio                               person_list [i-1].fio[j]

Массив структурных переменных можно описать и следующим образом:

struct { char name[20];

       char title[44];

       int year;

       float price;

} books[25];

Тогда к полю year в i-ом элементе массива структур books можно обратиться  следующим образом:

books[i]. year =2007;

(*(books+i)). year =2007;

(books+i)->year =2007;

 

Примеры работы со структурами

1. Определение структурного типа complex, представляющего комплексные числа, заданные в алгебраической форме, и определение структурных переменных x, y этого типа:

struct complex { float re;    //действительная часть числа

            float im;    //мнимая часть числа

} x, y;                 

 

При этом x.re – доступ к полю действительной части комплексного числа x,

              y.im – доступ к полю мнимой части комплексного числа y,

 

Тогда функции для ввода, вывода, сложения комплексных чисел могут выглядеть так:

struct complex { float re, im;}; //определение структурного типа

 

complex read ();              //прототип функции ввода комплексного числа

void print (complex);        //прототип функции вывода комплексного числа на экран

void add (complex, complex, complex*); //прототип функции сложения комплексных чисел

void add1 (const complex&, const complex&, complex&);

int main()

{

complex c1, c2, c3,c4;        //определение комплексных чисел

c1 = read();                  //вызов функции ввода числа

c2 = read();

 

add (c1, c2, &c3);    

print(c1); cout << "\t + \t" << endl;

print (c2); cout << " = " << endl;

print (c3);

cout << endl;

 

add1 (c1, c3, c4);

print(c1); cout << "\t + \t" << endl;

print (c3); cout << " = " << endl;

print (c4);

 

_getch();

return 0;

}

 

complex read()

{

complex c;

cout << "re, im:"<< endl;

cin >> c.re >> c.im;

return c;

}

 

void print (complex c)

{

 cout << c.re << " + i*" << c.im << endl;

return;

}

 

void add (complex c1, complex c2, complex *c3)

{

c3->re = c1.re +c2.re;  //или (*c3).re = c1.re + c2.re;      

c3->im= c1.im +c2.im;

return;

}

void add1 (const complex &c1, const complex &c2, complex &c3)

{

c3.re = c1.re +c2.re;      

c3.im= c1.im +c2.im;

return;

}

   

2. Определение структурного типа racion, представляющего понятие «рациональное число» и набор функций для сокращения, печати, деления рациональных чисел:

struct racion {int chis, znam;}; //определение структуры

 

void put (racion);            //прототипы функций

racion sokr (racion A);

void div (racion A, racion B, racion *C);

 

int main()

{

racion A, B, C;

puts ("racion1, racion2:?");

scanf ("%d%d%d%d", &A.chis, &A.znam, &B.chis, &B.znam); //ввод чисел

div(A, B, &C);                     //вызов функции деления чисел

printf (":"); put(A);

printf ("\tna\t"); put(B);

printf ("\n="); put(C); //вывод результата

_getch();

return 0;

}

 

 void put (racion A)   //функция выводит на экран «рациональное число»

{if (A.chis * A.znam <0) printf ("-");

A.chis = abs(A.chis);

A.znam = abs(A.znam);

printf("%d / %d", A.chis, A.znam);

}

 

void div (racion A, racion B, racion *C) //функция делит 2 рациональных числа

{

A=sokr(A);

B= sokr (B);

C->chis = A.chis*B.znam;

C->znam = A.znam*B.chis;

*C= sokr (*C);

}

 

racion sokr (racion A)  //функция выполняет сокращение «рационального числа»

{

int i, min;

if (abs(A.chis) > abs(A.znam)) min= abs(A.znam);

else min = abs(A.chis);

for (i=min; i>1; i--)

if(A.chis % i ==0 && A.znam % i ==0) break;

A.chis /=i;

A.znam /=i;

return A;

}

 

3. Рассмотрим программу, позволяющую по паре чисел (год, порядковый номер дня) получить название и число месяца:

struct date {

       int d, m, y; //день, месяц, год

        char *mname; //название месяца

} md;

     

//двумерный массив с количеством дней в месяце для високосного и невисокосного года

static int dofm[2][12]={{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},

            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};

 

//массив строк с названием месяцев

static char *name[ ]={"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};

 

void monthd(date*, int); //прототип функции пересчета

//значение года передается функции в поле «год» структурной переменной,

//пересчитанные значения дня и месяца возвращаются в этой же переменной,

//поэтому значение структурной переменной передается по указателю

 

int main()

{int yd;                   //порядковый номер дня года

 cout << "god, den?";

 cin >> md.y >> yd;     //ввод значений года  и порядкового номера дня

 monthd (&md, yd);    //вызов функции пересчета

 md.mname = name[md.m];  //присваивание названия месяцу

 cout << md.d <<" " << md.mname<< endl;

 _getch();

return 0;

}

 

void monthd(date *md, int yd)

{int i, v;

 v = (!(md->y%4) && (md->y%100) ||!(md->y%400)); //проверка на високосность

 if (yd > 365+v)

   {cout << "wrong number"; _getch(); exit(1);} //проверка значения дня года

 md->d = yd;             //подготовка начального значения для поля md->d

 

 for (i=0; md->d > dofm[v][i]; i++) //пересчет порядкового значения дня года

             md->d -= dofm[v][i]; //в день месяца

 md->m=i;                          //присваивание значения месяцу

}

 

Примеры использования объединений

Определение битовых полей

Язык С++ допускает использование в структурах и объединениях в качестве полей данных особого типа полей – битовых. Каждое битовое поле представляет целое или беззнаковое целое значение, занимающее в памяти фиксированное число битов. Число связанных бит – ширина поля.

 

Общий синтаксис описания битового поля:

тип_поля [имя_поля]: ширина_поля;

Члены битовых полей могут иметь значения базовых целых типов (знаковых или беззнаковых). Эти ключевые слова записываются в поле «тип_поля». Для переносимости программ лучше указывать служебные слова 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 битов)

 

 

  Примеры использования битовых полей

Вариант 2.

Используется функция, которая упаковывает в байт остатки от деления на 16 двух чисел

int main()

{

int a=36, b=20;           //два числа для формирования кода символа ‘D’

cout << cod(a, b) << endl;

_getch();

return 0;

}

 

unsigned char cod (int a, int b)

{ union {   

          unsigned char z;       

       struct {unsigned int x:4;

                 unsigned int y:4;

       } hh;

} un;

un.hh.x=a%16;   //остаток равен 4

un.hh.y=b%16;   //остаток равен 4

return un.z;         //возвращает символ с кодом 44

}

Лекция 18

Структуры. Объединения. Поля битов в структурах

Структура как пользовательский тип и совокупность данных. 1

Определение шаблона структуры и структурной переменной. 1

Расположение структурных переменных в памяти. 5

Инициализация структурных переменных. 7

Вложенные структуры.. 7

Операции над структурными переменными. 8

Массив структур. 10

Структура в качестве аргумента функции. 11

Примеры работы со структурами. 12

Объединение как пользовательский тип и совокупность данных. 15

Определение объединения и переменной объединяющего типа. 15

Примеры использования объединений. 17

Получение внутреннего представления вещественного числа. 17

Использование перечисляемого типа для обращения к полям объединения. 17

Битовые поля структур и объединений. 19

Определение битовых полей. 19

Примеры использования битовых полей. 20

Вывод значений битовых полей. 20

Формирование кода символа с помощью битовых полей объединения. 21

Формирование байта и вывод на экран его двоичного представления. 22



Поделиться:


Последнее изменение этой страницы: 2021-12-15; просмотров: 34; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.16.51.3 (0.166 с.)