- •Часть 1
- •Практическое занятие 1. Работа в среде Microsoft Visual Studio
- •Проекты и решения
- •Создание консольного приложения
- •Отладка в Visual Studio
- •Отладка программ
- •Практическое занятие 3. Операции и выражения. Линейные программы Операции и выражения
- •Логические операции
- •Поразрядные (побитовые) операции
- •Практическое занятие 4. Разветвляющиеся алгоритмы
- •If (выражение) оператор_1 else оператор_2
- •Операции сравнения (отношения)
- •Тернарная (условная) операция
- •Выражение_1 ? выражение_2 : выражение_3
- •Практическое занятие 5. Организация циклов. Операторы цикла
- •Оператор while
- •Оператор do…while
- •Оператор for
- •Операторы передачи управления Оператор break
- •Оператор continue
- •Указатели
- •Инициализация указателей
- •Операции над указателями
- •Одномерные массивы
- •Практическое занятие 7. Двумерные массивы. Организация работы с динамической памятью Двумерные массивы
- •Динамические массивы
- •Практическое занятие 8. Структуры. Форматный ввод/вывод данных. Структуры в языке с
- •Форматный ввод/вывод данных в стиле языка с
- •Int printf(строка_форматир-я [, список_переменных]);
- •Int scanf(const char * строка_форматирования,
- •Практическое занятие 9. Функция. Способы передачи параметров в функцию.
- •Выход из функции
- •Прототип (описание, объявление) функции
- •Рекурсия
- •Передача параметров в функцию
- •Передача массивов в качестве параметров функции
- •Практическое занятие 10. Перегрузка функций. Шаблоны функций Перегрузка функций
- •Перегрузка и область видимости
- •Шаблоны функций
- •Прототип шаблона
- •Параметры шаблона, не являющиеся типами
- •Явная специализация шаблонной функции
- •Директива #include
- •Директива #define
- •Символических констант
- •Макроимён, управляющих условной компиляцией:
- •Препроцессорные операторы # и ##
- •Директива #undef
- •Директивы условной компиляции #if, #ifdef, #ifndef
- •Вспомогательные директивы
- •Практическое занятие 12. Поразрядные операции Операции с разрядами Машинное слово
- •Представление машинных слов в программе
- •Технология работы с машинными словами
- •Поразрядная операция и
- •Поразрядная операция или
- •Операция поразрядной инверсии
- •Поразрядная операция исключающее или
- •Операция сдвиг влево
- •Операция сдвиг вправо
- •Формы представления числовых данных Целое без знака
- •Представление отрицательных чисел Дополнительный код
- •Преобразование типов операндов в выражениях
- •Стандартные программные решения Преобразование типов операндов в выражениях
- •Подсчет количества единичных битов
- •Упаковка данных полями переменной длины
- •Машинная арифметика – целые произвольной точности
- •01000 Хххххххх 00011 ххх 10000 хххххххххххххххх 00000.
- •Практическое занятие 13. Пространства имен
- •Пространство имен std
- •Приложение 1. Простые алгоритмы сортировки одномерных массивов
- •Сортировка простыми обменами (пузырьковая)
- •Сортировка простыми вставками (прямого включения)
- •Приложение 2. Создание файла с результатами препроцессорной обработки в среде Visual Studio
- •Создание файла с результатами препроцессорной обработки из командной строки
- •Приложение 3. Использование генератора случайных чисел
- •Рекомендуемая литература
- •Содержание
Преобразование типов операндов в выражениях
Преобразования базовых типов данных, соответствующих целым числам, не всегда сохраняют значения переменных и могут приводить к трудно обнаруживаемым ошибкам. В ряде случаев необходимо апеллировать к внутренним формам представления и действиям над ними. Преобразование формы представления может включать в себя:
- преобразование целой переменной в переменную с плавающей точкой, и наоборот;
- увеличение или уменьшение разрядности машинного слова, то есть «растягивание» или «усечение» целой переменной;
- преобразование знаковой формы представления целого в беззнаковую, и наоборот.
Уменьшение разрядности машинного слова всегда происходит путем отсечения старших разрядов числа, что может привести к ошибкам потери значащих цифр и разрядов:
int n=0x7654;
char с; с = n; //Потеря значащих цифр (0x54)
Увеличение разрядности приводит к появлению дополнительных старших разрядов числа. При этом способ их заполнения зависит от формы представления целого и обеспечивает сохранение значения переменной в данной форме представления:
- для беззнаковых целых заполнение производится нулями;
- для целых со знаком дополнительные разряды заполняются одним и тем же значением знакового (старшего) разряда.
int n; unsigned u;
// Значение n=0xFF84
char с=0х84; n= с;
//Значение u=0x0084
unsigned char uc=0x84; u = uc;
При преобразовании вещественного к целому происходит потеря дробной части, при этом возможно возникновение ошибок переполнения и потери значащих цифр, когда полученное целое имеет слишком большое значение.
double d1 =855.666, d2=0.5E16;
int n;
n = d1; // Отбрасывание дробной части
n = d2; // Потеря значимости
Преобразование знаковой формы в беззнаковую и обратно не сопровождается изменением значения целого числа и вообще не приводит к выполнению каких-либо действий в программе. В таких случаях транслятор «запоминает», что форма представления целого изменилась, и только.
int n = -1;
unsigned d;
d = n; // Значение d=0xFFFF (-1)
Самое главное для программиста, что в языке не предусмотрены средства автоматической реакции на ошибки преобразования типов данных, поэтому «отлавливать» их должна сама программа.
Преобразования типов данных операндов происходят в программе в трех случаях:
при выполнении операции присваивания, когда значение переменной или выражения из правой части запоминается в переменной в левой части;
при прямом указании на необходимость изменения типа данных переменной или выражения для чего используется операция явного преобразования типа;
при выполнении бинарных операций над операндами различных типов, когда более «длинный» операнд превалирует над более «коротким», вещественное - над целым, а беззнаковое - над знаковым.
В последнем случае неявные преобразования выполняются в такой последовательности: короткие типы данных (знаковые и беззнаковые) удлиняются до int и double, а выполнение любой бинарной операции с одним long double, double, long, unsigned ведет к преобразованию другого операнда в тот же тип. Это может сопровождаться перечисленными выше действиями: увеличением разрядности операнда путем его «удлинения», преобразованием в форму с плавающей точкой и изменением беззнаковой формы представления на знаковую, и наоборот.
Следует обратить внимание на одну тонкость: если в процессе преобразования требуется увеличение разрядности переменной, то на способ ее «удлинения» влияет только наличие или отсутствие знака у самой переменной. Второй операнд, к типу которого осуществляется приведение, на этот процесс не влияет:
long k=0x21;
unsigned short d=0xFF00;
//0x00000021 + 0xFF00 =
//=0x00000021 + 0x0000FF00 = 0x0000FF21
cout<<hex<<k + d<<’\n’;
В данном случае производится преобразование короткого целого без знака (unsigned) в длинное целое со знаком (long). В процессе преобразования «удлинение» переменной d производится как беззнаковое (разряды заполняются нулями), хотя второй операнд и имеет знак.
Рассмотрим еще несколько примеров.
int i; i=0xFFFF;
Целая переменная со знаком получает значение FFFF, что соответствует -1 для знаковой формы в дополнительном коде. Изменение формы представления с беззнаковой на знаковую не сопровождается никакими действиями.
short i = 0xFFFF;
int k; k=i;
Преобразование short в int сопровождается «удлинением» переменной, что c учетом представления i со знаком дает FFFFFFFF, то есть целое со значением -1.
unsigned short n =0xFF00;
int i;
i = n;
Переменная n «удлиняется» как целое без знака, то есть переменная i получит значение 0000FF00.
short i; unsigned short u;
i = u= 0xFFFF;
if (i > 5) … // "Ложь"
if (u > 5) ... // "Истина"
Значения переменных без знака и со знаком равны FFFF или -1. Но результаты сравнения противоположны, так как во втором случае сравнение проводится для беззнаковых целых по их абсолютной величине, а в первом случае - путем проверки знака результата вычитания, то есть с учетом знаковой формы представления чисел.
