![](/user_photo/2706_HbeT2.jpg)
- •Предисловие
- •Глава 1. Основные понятия
- •1.1. Элементы языка программирования
- •1.2. Процесс создания программы
- •1.3. Первая программа
- •1.4. Состав программы
- •Глава 2. Средства разработки на C++
- •2.1. Системы Turbo C++ 3.0/Borland C++ 3.1
- •2.2. Система C++ Builder
- •Глава 3. Работа с числовыми данными
- •3.1. Целые типы
- •3.2. Числа с плавающей точкой
- •3.3. Ввод и вывод чисел
- •3.4. Логический тип и логические операции
- •3.5. Математические функции
- •Глава 4. Операторы. Ключевые слова
- •4.1. Операторы
- •4.2. Приоритеты операторов
- •4.3. Ключевые слова
- •4.4. Структура программы
- •4.5. Константы
- •Задачи - . Простейшие вычисления
- •Глава 5. Управление и циклы
- •5.1. Условный оператор
- •5.2. Операторы цикла
- •5.3. Переключатель
- •5.4. Операторы break и continue
- •Задачи -. Выбор и циклы
- •Глава 6. Массивы
- •6.1. Одномерные массивы
- •6.2. Двумерные массивы
- •Задачи -. Одно- и двумерные массивы
- •Глава 7. Функции
- •7.1. Определение функции
- •7.2. Формальные параметры и фактические аргументы
- •7.3. Автоматические и статические переменные
- •7.4. Прототипы функций
- •7.5. Массивы как аргументы функций
- •7.6. Внешние переменные
- •7.7. Рекурсия
- •7.8. Перегруженные имена функций
- •7.9. Аргументы функций по умолчанию
- •Задачи -. Функции
- •Глава 8. Символы и строки
- •8.1. Символы
- •8.2. Строки символов
- •Задачи -. Символы и строки
- •Глава 9. Препроцессор
- •9.1. Директивы препроцессора
- •9.2. Макросы
- •Задачи -. Макросы
- •Глава 10. Указатели и ссылки
- •10.1. Указатели и адреса
- •10.2. Указатели и массивы
- •10.3. Адресная арифметика
- •10.4. Символьные указатели
- •10.5. Массивы указателей
- •10.6. Указатели на функции
- •10.7. Ссылки
- •10.8. Операторы new и delete
- •Задачи -. Указатели и ссылки
- •Глава 11. О файлах и командной строке
- •11.1. Знакомство с файлами
- •11.2. Командная строка
- •11.3. Перенаправление стандартного ввода и вывода на файл
- •11.4. Аргументы командной строки
- •Задачи -. Файлы и командная строка
- •Глава 12. Работа с экраном дисплея
- •12.1. Текстовый режим
- •12.2. Графический режим
- •Задачи -. Работа с экраном
- •Глава 13. Внутреннее представление чисел
- •13.1. Двоичная система счисления
- •13.2. Беззнаковые целые
- •13.3. Двоичный дополнительный код
- •13.4. Двоичный код с избытком
- •13.5. Побитовые операторы
- •13.6. Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8. Преобразование типов
- •Задачи -. Побитовые операторы
- •Глава 14. Структуры, перечисления, объединения
- •14.1. Объявление структур
- •14.2. Структуры и функции
- •14.3. Указатели на структуры
- •14.4. Массивы структур
- •14.5. Перечисления
- •14.6. Объединения
- •14.7. Битовые поля
- •14.8. О бинарных файлах
- •Задачи -. Структуры
- •Глава 15. Классы
- •15.1. Структуры в C++. Инкапсуляция
- •15.2. Встроенные функции
- •15.3. Классы. Скрытие данных
- •15.4. Конструкторы
- •15.5. Статические члены класса
- •15.6. Друзья класса
- •15.7. Копирование объектов класса
- •15.8. Управление доступом
- •15.9. Ссылка на себя
- •15.10. Деструкторы
- •Задачи -. Работа с классами
- •Глава 16. Программы из нескольких файлов
- •16.1. Работа с проектами
- •16.2. Область действия имен
- •16.3. Заголовочные файлы
- •16.4. Пространства имен
- •Задачи -. Работа со стеком
- •Глава 17. Перегрузка операторов
- •17.1. Правила перегрузки операторов
- •Задачи -. Перегрузка операторов
- •Глава 18. Конструктор копирования и оператор присваивания
- •18.1. Проблемы при копировании
- •Задачи -. Конструктор копирования
- •Глава 19. Ввод и вывод
- •19.1. Вывод
- •19.2. Ввод
- •19.3. Ввод и вывод определяемых пользователем типов
- •19.4. Работа с файлами
- •Глава 20. Взаимоотношения классов
- •20.1. Объекты как члены класса
- •20.2. Конструкторы встроенных типов
- •20.3. Наследование
- •20.4. Виртуальные функции
- •20.5. Абстрактные классы
- •20.6. Совместимость типов
- •20.7. Множественное наследование
- •Задачи -. Наследование классов
- •Глава 21. Шаблоны, исключения
- •21.1. Шаблоны
- •21.2. Шаблоны функций
- •21.3. Классы и шаблоны
- •21.4. Обработка исключений
- •21.5. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
![](/html/2706/175/html_zl27x8vZdH.bmrn/htmlconvd-ehB0QZ160x1.jpg)
160 13
для нахождения модуля отрицательного числа, представленного в двоичном дополнительном коде, нужно заменить все его разряды на обратные и добавить 1.
Найдем, для примера, сумму 1 + (–1):
+ 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0
Девятый разряд выходит за границы разрядной сетки и отбрасывается, поэтому получается правильный результат 0.
Формально результат сложения 1 + (–1)
равен
1000000002 = 28.
Такой же результат получается при сложении любых двух одинаковых по модулю чисел противоположного знака, то есть битовые комбинации противоположных по знаку чисел дополняют друг друга до 28. Отсюда произошло название данного способа представления чисел.
Преимущество двоичного дополнительного кода состоит в том, что процессору достаточно уметь выполнять только две операции: сложения и получения обратного по знаку числа, вычитание сводится к этим операциям, так как разность любых чисел a – b можно представить в виде суммы a + (-b).
Ограниченность разрядной сетки приводит в предельных случаях к парадоксальным результатам. Вычислим, например, 127 + 1:
+0 1 1 1 1 1 1 1
0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0
Получили:
127 + 1 = –128.
Другие знаковые типы используют также двоичный дополнительный код, только имеют большее число разрядов.
13.4.Двоичный код с избытком
Внекоторых случаях для отрицательных чисел используется другое представление, называемое двоичным кодом с избытком, табл.50.
Здесь битовые комбинации и соответствующие им числа расположены по возрастанию, нуль занимает центральное положение.
![](/html/2706/175/html_zl27x8vZdH.bmrn/htmlconvd-ehB0QZ161x1.jpg)
Внутреннее представление чисел |
161 |
Если рассматривать битовые комбинации просто как двоичные числа, то для получения соответствующего числового значения нужно из двоичного числа вычесть 128. Можно сказать и по-другому: числа хранятся в виде, увеличенном на 128, отсюда и происходит название данного представления: код с избытком.
Двоичная нотация с избытком применяется для хранения порядка чисел с плавающей точкой.
Таблица 51. Код с избытком 128
Битовая комбинация Числовое значение |
|
1111 1111 |
127 |
1111 1110 |
126 |
… |
… |
1000 0011 |
3 |
1000 0010 |
2 |
1000 0001 |
1 |
1000 0000 |
0 |
0111 1111 |
–1 |
0111 1110 |
–2 |
0111 1101 |
–3 |
… |
… |
0000 0001 |
–127 |
0000 0000 |
–128 |
13.5. Побитовые операторы
Побитовые операторы применимы только к целым типам. Они действуют на отдельные разряды двоичного представления чисел. Напомним, что имеются следующие побитовые операторы:
| – побитовое логическое ИЛИ, & – побитовое логическое И,
^ – побитовое исключающее ИЛИ, ~ – побитовое логическое отрицание, << – сдвиг влево, >> – сдвиг вправо.
В табл.52 представлены результаты выполнения побитовых операторов над двумя битами a и b.
![](/html/2706/175/html_zl27x8vZdH.bmrn/htmlconvd-ehB0QZ162x1.jpg)
162 13
Таблица 53. Таблица истинности побитовых логических операторов
a |
b |
a|b |
a&b |
a^ |
~a |
|
|
|
|
b |
|
1 |
1 |
1 |
1 |
0 |
0 |
0 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
Оператор побитового ИЛИ можно использовать для установки в 1 заданных разрядов числа, например, после выполнения инструкции
y = x | 017;
четыре младших разряда y будут равны 1. Действительно, пусть x, y занимают 1 байт памяти и x имеет исходное значение
|
x7x6x5x4 x3x2x1x0, |
|
|
|||||||
тогда |
|
|
|
|
|
|
|
|
|
|
x: |
| |
x7 |
x6 |
x5 |
x4 |
x3 |
x2 |
x1 |
x0 |
|
017: |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
||
y= |
|
|
x7 |
x6 |
x5 |
x4 |
1 |
1 |
1 |
1 |
Оператор побитового И можно использовать для установки в 0 заданных разрядов числа, например, после выполнения инструкции
y = x & 017;
четыре старших разряда y будут нулями, а младшие разряды не изменятся. Пусть, например, x имеет исходное значение:
|
x7x6x5x4 x3x2x1x0, |
|
|
||||||
тогда |
|
|
|
|
|
|
|
|
|
x: |
& |
x7 |
x6 |
x5 |
x4 |
x3 |
x2 |
x1 |
x0 |
017: |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
1 |
|
y= |
|
0 |
0 |
0 |
0 |
x3 |
x2 |
x1 |
x0 |
Оператор побитового исключающего ИЛИ можно использовать для изменения заданных разрядов на противоположные. Например, пусть переменная x имеет исходное значение:
1100 0101.
Найдем его значение после выполнения инструкции: x = x ^ 017;
![](/html/2706/175/html_zl27x8vZdH.bmrn/htmlconvd-ehB0QZ163x1.jpg)
Внутреннее представление чисел |
163 |
x:1 1 0 0 0 1 0 1
^0 0 0 0 1 1 1 1017:
x=x^017 |
1 1 0 0 1 0 1 0 |
: |
|
Видно, что младшие разряды x приняли противоположное значение, а старшие не изменились.
Оператор ~ инвертирует (меняет на противоположные) все биты операнда. Пусть, например, x имеет код:
1100 0101.
После выполнения инструкции y = ~x; двоичный код для y будет:
0011 1010.
Операторы << и >> сдвигают свои первые операнды соответственно влево и вправо на число позиций, заданных вторым операндом. Значение второго операнда этих операторов должно быть неотрицательным.
Так,
y << 2
сдвигает значение y влево на 2 разряда, заполняя освобождающиеся разряды нулями, что, кстати, эквивалентно умножению на 4. Если y имеет тип char и двоичное представление
1100 01012 = –0011 10112 = –5910,
то выражение y << 2 имеет значение:
1100 0101 << 2 = 0001 01002 = 2010.
Умножим теперь -59 на 4, что эквивалентно четырехкратному сложению:
1 1 0 0 0 1 0 1
+1 1 0 0 0 1 0 1
+1 1 0 0 0 1 0 1
+1 1 0 0 0 1 0 1
0 0 0 1 0 1 0 0
Как видим, результат одинаков.
При сдвиге вправо беззнаковой величины освобождающиеся разряды заполняются нулями.
При сдвиге вправо знаковой величины происходит «размножение» знака, благодаря чему отрицательное число остается отрицательным после сдвига, а положительное – положительным
![](/html/2706/175/html_zl27x8vZdH.bmrn/htmlconvd-ehB0QZ164x1.jpg)
164 13
Сдвиг вправо на один разряд эквивалентен делению числа на 2. Пусть y имеет рассмотренное выше значение
1100 01012 = -5910. Значение выражения y >> 2 равно
(1100 0101 >> 2) = 111100 012 = -0000 11112 = -15. Это эквивалентно делению на 4 с отбрасыванием остатка.
Программа 35. Побитовые операторы
В программе выполняются побитовые операторы и выводятся их результаты в виде десятичных и двоичных чисел.
Для получения двоичного представления величин целого типа написана функция itobin. Предварительно инструкцией:
typedef char Typei;
вводится новое имя типа Typei для типа char. Тип Typei указан как тип аргумента функции itobin. Чтобы использовать itobin для другого целого типа, нужно просто переопределить тип Typei.
Алгоритм работы itobin состоит в следующем. Создается переменная onebit, имеющая вначале одну единичку в самом правом разряде. Эта величина сравнивается с аргументом n с помощью оператора & и сдвигается после каждого сравнения влево. Если результат сравнения не 0, значит в соответствующем разряде n и onebit единичка, а в противном случае 0. В строку s заносится соответствующий символ. Затем строка s реверсируется библиотечной функцией
char *strrev(char *s);
которая изменяет порядок символов в s на обратный и возвращает указатель на преобразованную строку.
// Файл BitOper.cpp |
|
#include <string.h> |
|
typedef char Typei; |
// Typei обозначает целый тип |
// itobin: формирует строку из 0 и |
1 с двоичным представлением n, |
// возвращает указатель на s |
|
char* itobin(Typei n, char*s) |
|
{ |
|
int i, d;
int size = sizeof(Typei) * 8; // Размер целого типа в битах Typei onebit = 1;
// Заполнение s двоичными цифрами, начиная с последней
Внутреннее представление чисел |
165 |
for(i = 0; i < size; i++, onebit <<= 1) s[i] = n & onebit ? '1': '0';
s[i] = '\0';
strrev(s); // Реверсирование строки return s;
}
#include <iostream.h> |
|
#include <conio.h> |
|
int main() |
|
{ |
|
char s[33]; |
// Массив для двоичных цифр |
cout << "\nРабота с беззнаковыми \n"; unsigned char p = 100, q = 200, sum, diff, q1;
cout << "p = " << int(p) << " = " << itobin(p, s) << endl; cout << "q = " << int(q) << " = " << itobin(q, s) << endl; sum = p + q; diff = p - q;
cout << "p + q = " << int(sum) << ", p - q = " << int(diff) << endl; q1 = q >> 2;
cout << "q >> 2 = " << int(q1) << " = " << itobin(q1, s) << endl; cout << "Работа со знаковыми \n";
char z = 127, z1 = z + 1;
cout << "z = " << int(z) << " = " << itobin(z, s);
cout << ", z + 1 = " << int(z1) << " = " << itobin(z1, s)<< endl; char x = -59, y;
cout << "x = "<< int(x) << " = " << itobin(x, s) << endl; y = x | 017;
cout << "x | 017 = " << int(y) << " = " << itobin(y, s) << endl; y = x & 017;
cout << "x & 017 = " << int(y) << " = " << itobin(y, s) << endl; y = x ^ 017;
cout << "x ^ 017 = " << int(y) << " = " << itobin(y, s) << endl; y = ~x;
cout << "~x = " << int(y) << " = " << itobin(y, s) << endl; y = x << 2;
cout << "x << 2 = " << int(y) << " = " << itobin(y, s) << endl; y = x >> 2;
cout << "x >> 2 = " << int(y) << " = " << itobin(y, s) << endl; getch();
return 0;
}
Для вывода числового значения переменной типа char использовано преобразование типа int(p), явно приводящее величину к типу int. Без этого преобразования инструкция