Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Tekhnologia_programmirovania.pdf
Скачиваний:
182
Добавлен:
08.04.2015
Размер:
1.76 Mб
Скачать

194 14

14.7. Битовые поля

Имеется возможность размещать в одном слове несколько объектов, что позволяет экономить память. Если известен диапазон значений некоторой величины, то нетрудно оценить количество бит для ее кодирования. Совокупность бит, необходимая для кодирования величины, называется полем. Битовые поля используются в качестве элементов структур. При объявлении таких элементов указывается их ширина в битах. Ширина битового поля не может превышать ширину слова, но структура, объединяющая битовые поля, может занимать несколько слов. Безымянные битовые поля служат для пропуска нескольких разрядов. Ширина, равная нулю, используется, когда требуется выйти на границу следующего слова. Битовые поля размещаются в слове, начиная с его младших разрядов. С битовыми полями можно работать как с малыми целыми числами.

14.8. О бинарных файлах

Для того, чтобы открыть файл как бинарный, функцию open следует вызвать с двумя аргументами. Первый аргумент задает имя открываемого файла, а второй определяет режим работы с файлом. Таких режимов может быть три: чтение, запись, чтение и запись

(изменение).

В

файле

fstream.h

определены

специальные

константы – флаги,

имеющие

по одной

единичке в

своих разрядах,

которые можно использовать для указания режима работы с файлами:

ios::in

открыть файл на чтение,

ios::out

открыть файл на запись,

ios::binary

открыть файл как бинарный, а не как текстовый.

Данные флаги можно комбинировать с помощью побитового логического оператора ИЛИ (|).

Для чтения из бинарного потока применяют функцию: read(char *str, size_t count);

которая читает из потока count байтов и сохраняет их в массиве, начало которого указывает str.

Для записи в бинарный поток служит функция: write(const char *str, size_t count);

направляющая в поток count байтов из массива, на который указывает

str.

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

Структуры, перечисления, объединения 195

прочитан или записан при следующей операции ввода/вывода. Положением текущего указателя в выходном потоке можно управлять с помощью функции:

ostream& seekp(long offs, seek_dir dir);

Текущую позицию во входном потоке можно изменить функцией istream& seekg(long offs, seek_dir dir);

Первый параметр offs этих функций задает число позиций, на которое надо переместить текущий указатель, а второй параметр dir назначает точку отсчета, от которой надо произвести смещение. Для указания точки отсчета можно использовать перечислимые константы из файла iostream.h:

enum seek_dir { beg, cur, end };

beg

– смещаться от начала файла,

cur

смещаться от текущей позиции,

end

смещаться от конца файла.

Например, в программе 40 открывается файловый поток f на чтение и запись. Текущий указатель перемещается в начало файла следующей инструкцией:

f.seekg(0, ios::beg);

Программа 40. Анализ успеваемости

В данном примере речь идет об анализе успеваемости некоторой студенческой группы в одну из экзаменационных сессий. Программа создает файл, содержащий фамилии студентов и их оценки за 4 экзамена. Пусть экзаменационная оценка может иметь 4 значения: неуд, уд, хор и отл, в этом случае для ее кодирования достаточно двух бит, так как с помощью двух бит можно создать 4 комбинации. В программе объявлена структура marks с четырьмя полями шириной по 2 бита, которые могут содержать значения оценок. Таким образом, все 4 оценки студента можно разместить в одном байте.

Для хранения как фамилии студента, так и его оценок используется структура student.

Предусмотрены два режима работы программы. Если первую строку программы записать в виде

# define EXIST_FILE 0 // Нет файла с результатами сессии

то программа попросит ввести имя создаваемого файла, в который будет записывать вводимые данные. Если первая строка имеет вид

196

14

 

# define EXIST_FILE 1

// Имеется файл с результатами сессии

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

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

// Файл Progress.cpp

# define EXIST_FILE 0 // Нет файла с результатами сессии

/* Макрос EXIST_FILE устанавливается в нуль,

если создается новый файл, и в единицу, если файл существует */

struct marks {

 

unsigned ex1: 2;

// Целое значение после

unsigned ex2: 2;

// двоеточия – это ширина поля в битах

unsigned ex3: 2;

 

unsigned ex4: 2;

 

};

 

struct student{

 

char fam[20];

// fam - стpока для фамилии

marks rez;

// rez - поле с оценками

};

 

enum numbers{neud = 0, ud = 1, hor = 2, otl = 3};

/* Пеpечисление numbers вводит имена для заданных целых значений */

#include <iostream.h>

// prn_mrk: печать оценки в словесной форме void prn_mrk(int mrk)

{

mrk == neud ? cout << "неуд " : mrk == ud ? cout << "уд " : mrk == hor ? cout << "хор " : cout << "отл ";

}

#include <stdlib.h> #include <fstream.h> #include <conio.h>

void main()

{

Структуры, перечисления, объединения 197

student st;

 

int m1, m2, m3, m4, i;

 

char filename [20];

// Массив для имени файла

fstream f;

// Файловый поток

cout << "\n Программа анализа результатов сессии \n"; cout << "Введите имя файла \n";

cin.getline(filename, 20);

#if EXIST_FILE

f.open(filename, ios::in|ios::binary);

if(!f){

cerr << " Файл не найден \n"; exit(1);

}

#endif

//Если файл существует

//Файл открывается на чтение

//как бинарный

//Если файл открыть не удалось

//завершение программы

#if !EXIST_FILE

// Если файла пока нет

f.open(filename, ios::in|ios::out|ios::binary);// Файл открывается на

 

// чтение и запись как бинарный

if(!f){

// Если файл открыть не удалось

cerr << " Ошибка открытия файла \n";

exit(1);

// завершение программы

}

 

cout << "Вводите фамилии студентов и их оценки " "в виде чисел (2, 3, 4, 5). \n"

"Разделитель - пробел, конец ввода Ctrl+Z.\n";

while(cin >> st.fam >> m1 >>m2 >>m3 >> m4){ // Пока не достигнут // конец входного потока

st.rez.ex1 = m1 - 2; // Оценки хранятся в виде, st.rez.ex2 = m2 - 2; // уменьшенном на две единицы, st.rez.ex3 = m3 - 2; // так как отведенные для них поля

st.rez.ex4 = m4 - 2; // могут хранить значения только от 0 до 3

//Запись информации о студенте в файл f.write((char*)(&st), sizeof(student));

}

#endif

f.seekg(0, ios::beg);

// Переход к началу файла

cout << "\n РЕЗУЛЬТАТЫ СЕССИИ \n";

 

// Чтение и печать содержимого файла

 

while(f.read((char*)&st, sizeof(student)) != NULL){

cout << st.fam << ": " << st.rez.ex1 + 2 << ", " << st.rez.ex2 + 2 << ", "<< st.rez.ex3 + 2 << ", " << st.rez.ex4 + 2;

cout << "(";

 

prn_mrk(st.rez.ex1);

// Печать оценок