Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих (Стенли Липпман) 3-е хххх.pdf
Скачиваний:
86
Добавлен:
30.05.2015
Размер:
5.92 Mб
Скачать

С++ для начинающих

163

Упражнение 4.12

Даны два целых числа:

unsigned int ui1 = 3, ui2 = 7;

Каков результат следующих выражений?

(a)ui1 & ui2 (c) uil | ui2

(b)ui1 && ui2 (d) uil || ui2

Упражнение 4.13

Используя пример функции bit_on(), создайте функции bit_turn_on() (выставляет бит в 1), bit_turn_off() (сбрасывает бит в 0), flip_bit() (меняет значение на противоположное) и bit_off() (возвращает true, если бит равен 0). Напишите программу, использующую ваши функции.

Упражнение 4.14

В чем недостаток функций из предыдущего упражнения, использующих тип unsigned int? Их реализацию можно улучшить, используя определение типа с помощью typedef или механизм функций-шаблонов. Перепишите функцию bit_on(),применив сначала typedef, а затем механизм шаблонов.

4.12. Класс bitset

Таблица 4.4. Операции с классом bitset

Операция

Значение

Использование

 

 

 

test(pos)

Бит pos равен 1?

a.test(4)

any()

Хотя бы один бит равен 1?

a.any()

none()

Ни один бит не равен 1?

a.none()

count()

Количество битов, равных 1

a.count()

size()

Общее количество битов

a.size()

[pos]

Доступ к биту pos

a[4]

flip()

Изменить значения всех

a.flip()

flip(pos)

Изменить значение бита pos

a.flip(4)

set()

Выставить все биты в 1

a.set()

set(pos)

Выставить бит pos в 1

a.set(4)

reset()

Выставить все биты в 0

a.reset()

reset(pos)

Выставить бит pos в 0

a.reset(4)

Как мы уже говорили, необходимость создавать сложные выражения для манипуляции битовыми векторами затрудняет использование встроенных типов данных. Класс bitset упрощает работу с битовым вектором. Вот какое выражение нам приходилось писать в предыдущем разделе для того, чтобы взвести27-й бит:

С++ для начинающих

164

quiz1 |= 1<<27;

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

quiz1[27] = 1;

или

quiz1.set(27);

(В нашем примере мы не используем нулевой бит, чтобы сохранить естественнуюнумерацию. На самом деле, нумерация битов начинается с 0.)

Для использования класса bitset необходимо включить заголовочный файл:

#include <bitset>

Объект типа bitset может быть объявлен тремя способами. В определении по умолчанию мы просто указываем размер битового вектора:

bitset<32> bitvec;

Это определение задает объект bitset, содержащий 32 бита с номерами от 0 до 31. Все биты инициализируются нулем. С помощью функции any() можно проверить, есть ли в векторе единичные биты. Эта функция возвращает true, если хотя бы один бит отличен от нуля. Например:

bool is_set = bitvec.any();

Переменная is_set получит значение false, так как объект bitset по умолчанию инициализируется нулями. Парная функция none() возвращает true, если все биты равны нулю:

bool is_not_set = bitvec.none();

Изменить значение отдельного бита можно двумя способами: воспользовавшись функциями set() и reset() или индексом. Так, следующий цикл выставляет в 1

for ( int index=0; index<32; ++index ) if ( index % 2 == 0 )

каждый четный бит:

bitvec[ index ] = 1;

Аналогично существует два способа проверки значений каждого бита с помощью функции test() и с помощью индекса. Функция () возвращает true, если

if ( bitvec.test( 0 ))

соответствующий бит равен 1, и false в противном случае. Например:

// присваивание bitvec[0]=1 сработало!;

С++ для начинающих

165

cout << "bitvec: включенные биты:\n\t"; for ( int index = 0; index < 32; ++-index )

if ( bitvec[ index ] ) cout << index << " ";

Значения битов с помощью индекса проверяются таким образом: cout << endl;

bitvec.reset(0);

Следующая пара операторов демонстрирует сброс первого бита двумя способами: bitvec[0] = 0;

Функции set() и reset() могут применяться ко всему битовому вектору в целом. В

// сброс всех битов bitvec.reset();

if (bitvec.none() != true)

//что-то не сработало

//установить в 1 все биты вектора bitvec

if ( bitvec.any() != true )

этом случае они должны быть вызваны без параметра. Например:

// что-то опять не сработало

bitvec.f1ip( 0 ); // меняет значение первого бита bitvec[0].flip(); // тоже меняет значение первого бита

Функция flip() меняет значение отдельного бита или всего битового вектора:

bitvec.flip();

// меняет значения всех битов

Существуют еще два способа определить объект типа bitset. Оба они дают возможность проинициализировать объект определенным набором нулей и единиц. Первый способ явно задать целое беззнаковое число как аргумент конструктору. Начальные N позиций битового вектора получат значения соответствующих двоичных разрядов аргумента. Например:

bitset< 32 > bitvec2( Oxffff );

инициализирует bitvec2 следующим набором значений:

00000000000000001111111111111111

В результате определения

С++ для начинающих

166

bitset< 32 > bitvec3( 012 );

у bitvec3 окажутся ненулевыми биты на местах 1 и 3:

00000000000000000000000000001010

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

// эквивалентно bitvec3 string bitva1( "1010" );

bitvec4 тем же набором значений, что и bitvec3: bitset< 32 > bitvec4( bitval );

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

// подстрока с шестой позиции длиной 4: 1010 string bitval ( "1111110101100011010101" );

для битового вектора. Например:

bitset< 32 > bitvec5( bitval, 6, 4 );

Мы получаем то же значение, что и для bitvec3 и bitvec4. Если опустить третий

// подстрока с шестой позиции до конца строки: 1010101 string bitva1( "1111110101100011010101" );

параметр, подстрока берется до конца исходной строки: bitset< 32 > bitvec6( bitval, 6 );

Класс bitset предоставляет две функции-члена для преобразования объекта bitset в другой тип. Для трансформации в строку, состоящую из символов нулей и единиц, служит функция to_string():

string bitva1( bitvec3.to_string() );

Вторая функция, to_long(), преобразует битовый вектор в его целочисленное представление в виде unsigned long, если, конечно, оно помещается в unsigned long. Это видоизменение особенно полезно, если мы хотим передать битовый вектор функции на С или С++, не пользующейся стандартной библиотекой.

Кобъектам типа bitset можно применять побитовые операции. Например: bitset<32> bitvec7 = bitvec2 & bitvec3;

Объект bitvec7 инициализируется результатом побитового И двух битовых векторов bitvec2 и bitvec3.