Структуры и алгоритмы компьютерной обработки данных

Битовые поля

Показывать лекцию целиком

Цель лекции: изучить понятие, объявление и размещение в памяти битовых полей, доступ к битовым полям структуры или объединения и научиться решать задачи с использованием битовых полей на языке C++.

В отличие от других языков программирования С++ имеет структуру, называемую битовыми полями (полями битов), которая позволяет работать с отдельными битами. Битовое поле – это особый компонент структуры, определяющий длину отдельного ее элемента. Битовые поля полезны по нескольким причинам.

  • Если ограничено место для хранения информации, можно сохранить несколько логических переменных в одном байте.
  • Некоторые интерфейсы устройств передают информацию, закодировав биты в один байт.
  • Некоторым процессам кодирования необходимо получить доступ к отдельным битам в байте.
  • Хотя все эти функции могут выполняться с помощью битовых операторов, битовые поля могут внести большую ясность в программу. Метод использования битовых полей для доступа к битам основан на структурах.

    Битовое поле – это элемент структуры, определенный как некоторое число битов, обычно меньшее, чем число битов в целом числе (оно по величине не превосходит машинного слова и зависит от реализации компилятора). Они предназначены для экономного размещения в памяти данных небольшого диапазона, обеспечивают удобный доступ к отдельным битам данных. Кроме того, с помощью битовых полей можно формировать объекты с длиной внутреннего представления, не кратной байту.

    Битовые поля обычно применяются в низкоуровневом программировании.

    Объявление битовых полей

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

    Синтаксис объявления типа структуры с битовыми полями:

    struct [ИмяСтруктуры] { Тип1 ИмяПоля1 : ШиринаПоля1
                            Тип2 ИмяПоля2 : ШиринаПоля2
                            ........................
                            ТипN ИмяПоляN : ШиринаПоляN
                          } ИмяСтруктуры;

    где structспецификатор типа;

    ИмяСтруктуры – идентификатор;

    Тип1, ... ТипN – тип поля, который может быть только int, возможно, со спецификатором unsigned или signed ;

    ШиринаПоля (длина) – целое неотрицательное десятичное число, значение которого обычно (в зависимости от реализации компилятора) не должно превышать длины машинного слова.

    Например:

    struct {
            int c1 : 4; 
            int c2 : 12; 
           } ab;

    Битовые поля длиной 1 должны объявляться как unsigned, поскольку 1 бит не может иметь знака. Битовые поля могут иметь длину от 1 до 16 бит для 16-битных сред и от 1 до 32 бит для 32-битных сред.

    Разрешается поле без имени (для этого надо указать только двоеточие и ширину), с помощью которого в структуру вводятся неиспользуемые биты (промежуток между значимыми полями). Нулевая ширина поля вводится, когда необходимо, чтобы следующее в данной структуре поле разместилось с начала очередного машинного слова.

    Например, если нам нужны только биты cts и dsr, то можно объявить структуру status_type следующим образом:

    struct status_type {
                        unsigned : 4; 
                        unsigned cts :1; 
                        unsigned dsr :4; 
                       } status;

    В структуре можно смешивать "обычные" элементы с битовыми полями.

    Например:

    struct emp {
                struct addr address;
                float pay;
                unsigned lay_off: 1; //работает или нет
                unsigned hourly: 1;//почасовая оплата или оклад
                unsigned deductions : 3; //удержание налога
               };

    Эта структура определяет запись по каждому служащему, в которой используется только один байт для хранения трех элементов информации: статус служащего, характер оплаты его труда и налоговая ставка. Без использования битовых полей для хранения этой информации пришлось бы занять несколько байтов.

    Вместо служебного слова struct можно употреблять union. В этом случае определяется объединение с битовыми полями. Битовые поля в объединениях используются для доступа к нужным битам того или иного объекта, входящего в объединение.

    Пример 1. В программе объединение позволяет сформировать код символа 'D' (равный 68):

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    union { char simb;
            struct { int x:5;
                     int y:3;
                   } hh;
          } cod;  
    int _tmain(int argc, _TCHAR* argv[]) {
      cod.hh.x = 4;
      cod.hh.y = 2;
      cout << cod.simb; // выводит на экран символ 'D'
      system("pause");
      return 0;
    }

    Доступ к элементам структур с битовыми полями

    Для обращения к битовым полям используются те же конструкции, что и для обращения к обычным элементам структур:

    ИмяСтруктуры.ИмяПоля
    (* УказательНаСтруктуру). ИмяПоля
    УказательНаСтруктуру -> ИмяПоля

    Например, для структуры xx с битовыми полями:

    struct {
            int a : 10; 
            int b : 14; 
           } xx;

    правомочны следующие операторы:

    xx.a=1;
    xx.b=48;
    xx.a=xx.b=0;

    Размещение битовых полей в памяти

    От реализации зависит порядок размещения в памяти полей одной структуры. Поля могут размещаться как слева направо, так и справа налево. Любой код программ, использующий битовые поля, зависит от компьютера и компилятора.

    Пример 2.

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    struct expl {
                 int i:2;
                 unsigned j:2;
                 int :2;
                 int k:2;
                 int dummy: 8;
                } my;
    int _tmain(int argc, _TCHAR* argv[]) {
      my.dummy = 0;
      my.i = 1;
      my.j = 3;
      my.k = -1;
      printf("%d\n", my);
      printf("Поля: %d\t%d\t%d", my.i, my.j, my.k);
      system("pause");
      return 0;
    }

    На рис 18.1 показывается, как выглядит переменная структурного типа my в памяти.

    (рис 18.1) Побитовое представление структуры

    Пример 3. Иллюстрация возможностей объединений и структур с битовыми полями.

    В программе вводятся значения двух целых переменных m и n, и остатки от их деления на 16 заносятся соответственно в четыре младших и в четыре старших разряда одного байта. Таким образом, выполняется некоторая кодировка введенных значений переменных m и n. Затем печатается изображение содержимого сформированного байта.

    Обратите внимание на использование объединения. В функции cod() запись данных производиться в элементы (битовые поля) структуры hh, входящей в объединение un, а результат выбирается из того же объединения un в виде одного байта. В функции binary() происходит обратное преобразование – в нее как значение параметра передается байт, содержимое которого побитово "расшифровывается" за счет обращения к отдельным полям структуры byte, входящей в объединение cod.

    //Структуры, объединения и битовые поля
    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    void binar (unsigned char); //прототип функции
    unsigned char cod (int, int); // прототип функции
    
    int _tmain(int argc, _TCHAR* argv[]) {
      unsigned char k;
      int m, n;
      printf("m=");  scanf("%d", m);
      printf("n=");  scanf("%d", n);
      k=cod(m,n);
      printf("cod=%u\n", k);
      binar(k);
      system("pause");
      return 0;
    }
    
    /*Упаковка в один байт остатков от деления на 16 двух целых чисел*/
    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;  
      un.hh.y=b%16;
      return un.z;
    }
    
    //двоичное представление байта
    void binar (unsigned char ch) {
      union { 
             unsigned char ss;
             struct { 
                     unsigned a0 : 1; 
                     unsigned a1 : 1;
                     unsigned a2 : 1;
                     unsigned a3 : 1;
                     unsigned a4 : 1;
                     unsigned a5 : 1;
                     unsigned a6 : 1;
                     unsigned a7 : 1;
                    } byte;
            } cod;
      cod.ss=ch;
      printf("Номер битов:     7  6  5  4  3  2  1  0\n");
      printf("Значение битов:  %d  %d  %d  %d  %d  %d  %d  %d\n", 
              cod.byte.a7, cod.byte.a6, cod.byte.a5, cod.byte.a4,
              cod.byte.a3, cod.byte.a2, cod.byte.a1, cod.byte.a0);
    }

    Результат выполнения программы:

    Первый вариант

    m=1                                    
    n=3                                    
    cod=49                                 
    Номер битов:     7  6  5  4  3  2  1  0
    Значение битов:  0  0  1  1  0  0  0  1

    Второй вариант

    m=0                                    
    n=1                                    
    cod=16                                 
    Номер битов:     7  6  5  4  3  2  1  0
    Значение битов:  0  0  0  1  0  0  0  0

    Ключевые термины

    Битовое поле – это элемент структуры, определенный как некоторое число битов, обычно меньшее, чем длина машинного слова.

    Размещение битовых полей – это порядок следования битов в машинных словах.

    Ширина битового поля – это количество битов, занимаемых полем.

    Краткие итоги

  • В качестве элемента структуры или объединения может быть использовано битовое поле.
  • Вне структур или объединений битовые поля использовать нельзя.
  • Существует три способа доступа к битовым полям.
  • К битовым полям нельзя обратиться по адресу размещения в памяти.
  • Расположение битовых полей зависит от реализации.
  • Ширина битовых полей не должна превосходить длины машинного слова. Допускается использование битового поля нулевой ширины.
  • Для битовых полей определена операция присваивания.
  • Лабораторная работа 18. Битовые поля

    Цель работы: изучить понятие, объявление и размещение в памяти битовых полей, доступ к битовым полям структуры или объединения и научиться решать задачи с использованием битовых полей на языке C++.

    При выполнении лабораторной работы для каждого задания требуется написать программу на языке С++, в которой выполнена разработка структуры с битовыми полями в соответствии с постановкой задачи, ввод данных элементов структуры, их обработка и вывод на экран в указанном формате. При этом битовые поля могут использоваться только в качестве полей структуры. Ввод данных осуществляется с клавиатуры с учетом требований к входным данным, содержащихся в постановке задачи. Ограничениями на входные данные являются максимальный размер строковых данных, диапазоны числовых типов полей структуры, максимально допустимый размер массива структур в языке С++.

    Теоретические сведения.

    Ознакомьтесь с материалом лекции 18.

    Задания к лабораторной работе.

    Выполните приведенные ниже задания.

  • Разработайте структуру, используя битовые поля для обозначения логических (битовых) значений. Структура Магазин: Наименование товара, Цена, Страна производства, Наличие в магазине, Соответствие стандарту РФ, Является товаром месяца. Объявите и заполните массив из пяти структур. Распечатайте информацию обо всех введенных товарах. Распечатайте информацию об имеющихся в магазине товарах, не соответствующих стандарту РФ.
  • Используя объединение с битовыми полями, определите четность беззнакового целого числа по анализу старшего бита (операцию деления с остатком не использовать).
  • Используя объединение с битовыми полями, определите кратность 8 беззнакового целого числа по анализу старших битов (операцию деления с остатком не использовать).
  • Указания к выполнению работы.

    Каждое задание необходимо решить в соответствии с изученными методами объявления и обработки структур с битовыми полями в языке С++. При выполнении заданий следует помнить. что в языке С++ битовые поля не используют автономно, а обязательно включают во множество полей структурного типа. При объявлении битовых полей необходимо выполнить комментирование используемых битов. При выполнении задач 2 и 3 используйте внутренне представление целых чисел. В задаче 1 следует объявить массив структур, организовав его вывод в виде таблицы.

    Следует реализовать каждое задание в соответствии с приведенными этапами:

  • изучить словесную постановку задачи, выделив при этом все виды данных;
  • сформулировать математическую постановку задачи;
  • выбрать метод решения задачи, если это необходимо;
  • разработать графическую схему алгоритма;
  • записать разработанный алгоритм на языке С++;
  • разработать контрольный тест к программе;
  • отладить программу;
  • представить отчет по работе.
  • Требования к отчету.

    Отчет по лабораторной работе должен соответствовать следующей структуре.

  • Титульный лист.
  • Словесная постановка задачи. В этом подразделе проводится полное описание задачи. Описывается суть задачи, анализ входящих в нее физических величин, область их допустимых значений, единицы их измерения, возможные ограничения, анализ условий при которых задача имеет решение (не имеет решения), анализ ожидаемых результатов.
  • Математическая модель. В этом подразделе вводятся математические описания физических величин и математическое описание их взаимодействий. Цель подраздела – представить решаемую задачу в математической формулировке.
  • Алгоритм решения задачи. В подразделе описывается разработка структуры алгоритма, обосновывается абстракция данных, задача разбивается на подзадачи. Схема алгоритма выполняется по ЕСПД (ГОСТ 19.003-80 и ГОСТ 19.002-80).
  • Листинг программы. Подраздел должен содержать текст программы на языке программирования С++, реализованный в среде MS Visual Studio 2010.
  • Контрольный тест. Подраздел содержит наборы исходных данных и полученные в ходе выполнения программы результаты.
  • Выводы по лабораторной работе.
  • Ответы на контрольные вопросы.
  • Контрольные вопросы

  • Какого типа объявляются битовые поля?
  • Почему нельзя объявить битовые поля вне структуры или объединения?
  • Как осуществляется адресация битовых полей?
  • От чего зависит порядок размещения в памяти битовых полей?
  • Возможно ли объявление массива битовых полей? Почему?
  • Возможно ли объявить безымянное битовое поле? Если да, то с какой целью оно используется?
  • Возможно ли объявить битовое поле нулевой длины? Если да, то с какой целью оно используется?
  • Существуют ли ограничения на длину битового поля?
  • С какой целью используются объединения с битовыми полями?
  • Какие существуют способы обращения к битовым полям?
  • Вернуться к учебному плану