Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Laboratornaya_Rabota_4_условие.docx
Скачиваний:
3
Добавлен:
12.07.2022
Размер:
54.24 Кб
Скачать

ЛАБОРАТОРНАЯ РАБОТА № 4

ФУНКЦИИ. БИТОВЫЕ ОПЕРАЦИИ. СИСТЕМЫ СЧИСЛЕНИЯ

1. Функции

Функция – это именованная последовательность описаний и операторов, выполняющая какое-либо законченное действие. Функция может принимать параметры и возвращать значение.

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

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

[ класс ] тип имя ([ список параметров ])

{ тело функции }

С помощью необязательного модификатора класс можно явно задать область видимости функции, используя ключевые слова extern и static:

extern – глобальная видимость во всех модулях программы (по умолча­нию);

static – видимость только в пределах модуля, в котором определена функция.

Тип возвращаемого функцией значения может быть любым, кроме массива и функции (но может быть указателем на массив или функцию). Если функция не должна возвращать значение, указывается тип void.

Список параметров определяет величины, которые требуется передать в функцию при ее вызове. Элементы списка параметров разделяются запятыми. Для каждого параметра, передаваемого в функцию, указывается его тип и имя (в объявлении имена можно опускать).

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

Тип возвращаемого значения и типы параметров совместно определяют тип функции.

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

При использовании в качестве параметра массива в функцию передается указатель на его первый элемент, иными словами, массив всегда передается по адресу. При этом информация о количестве элементов массива теряется, и следует передавать его размерность через отдельный параметр.

2. Битовые операции и упакованные данные

Обычно при программировании на языке высокого уровня минимальным размером данных является байт. Однако операционной системе часто приходится работать «на битовом уровне». Так, например, в регистре устройства каждый бит может иметь самостоятельное значение (чтение - запись, готов - не готов и т.д.).

Чтобы работать на битовом уровне, надо уметь устанавливать (в 1), сбрасывать (в 0) и определять значение отдельного бита целочисленной переменной, не меняя при этом остальных битов.

Биты в числе принято номеровать справа налево, начиная с 0.

Для установки в 1 отдельного бита целочисленной переменной необходимо выполнить операцию ИЛИ (OR, на языке C - |) со специально подобранным целым, которое принято называть маской. Для установки бита номер n в маске в соответствующей позиции должна стоять 1, а все остальные биты должны быть 0.

Пусть, например, необходимо установить в 1 5-ый бит целочисленной байтовой переменной x. В качестве маски нам потребуется комбинация битов 00100000, что на языке C можно записать с помощью шестнадцатеричной константы 0х20. Имеем:

x |= 0x20;

Сброс бита выполняется операцией И (AND, на языке C - &) с маской, в которой все 1, кроме одного 0, находящегося в соответствующей позиции (11011111):

x &= 0xDF;

Для определения значения бита сначала следует скопировать число во временную переменную (чтобы не испортить основное значение), затем сбросить (обнулить) все биты, кроме нужного, т.е. выполнить И с маской, состоящей из нулей и единственной 1 в нужной позиции. Если в результате получится 0 – значит, в исходной переменной был 0. Иначе – 1.

y = x;

y & = 0x20;

if (y > 0)

cout << 1

else

cout << 0;

Для определения значения бита можно также использовать операции сдвига:

i << j – сдвиг содержимого i на j разрядов влево; освободившиеся младшие разряды заполняются нулями;

i >> j – сдвиг содержимого i на j разрядов вправо; освободившиеся старшие разряды заполняются нулями.

y = x;

y <<=2 >>=7; // уничтожение всех битов, кроме

нужного

if (y > 0) cout << 1 else cout << 0;

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

Упакованные данные

Размер самой «маленькой» переменной – 8 бит. Но для хранения некоторой информации достаточно меньшего объема (например, информацию о поле человека можно записать всего в 1 бит). Можно хранить несколько значений в одной целочисленной переменной (например – упаковать дату в 16 бит, предназначив 7 бит для года, 4 для месяца и 5 – для дня), но тогда нужно уметь записывать значения в часть переменной и извлекать их оттуда. Очевидно, что оператор присваивания в этом случае не сработает.

Пусть, например, имеется 16-разрядное число и требуемое значение хранится в четырех битах, с 3-го по 6-ой.

Чтобы извлечь из числа значение, следует скопировать его в промежуточную переменную (которую можно будет менять). Затем следует обнулить в ней все биты, кроме нужных (т.е. с 0 по 2 и с 7 по 15). Для обнуления можно использовать операцию И со специально подобранным числом-маской или операции сдвига. После этого следует сдвинуть разряды, используя операцию >>, вправо так, чтобы младший разряд нужного значения попал в нулевой бит (в данном примере, на 3 бита вправо). Значение выделено.

Для записи необходимо использовать следующий порядок действий. Очистить старое значение (т.е. обнулить биты 3-7, используя И уже с другой, инвертированной маской). Затем присвоить вспомогательной переменной нужное значение, сдвинуть его влево на требуемое число бит (операция <<), и выполнить логическую операцию ИЛИ.