Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Основы разработки программ на языке С++ для систем информационной безопасности. Учебное пособие
.pdf
7.4. Неявное преобразование типа
41
Окончание табл. 18
№
вар.
Входные данные
Представление выходных данных
13
При вводе неверных значений
вывести программу из режима
отказа
Совершенные числа
14
Числа генерируются случайным образом
Числа, которые больше предыдущего
(первое число сравнить с последним)
15
По заданию
Выводятся первые 7 чисел, остальные
игнорируются программой
7.3. Преобразование типов данных в С++
Преобразованием типа представляет собой процесс конвертации
значения из одного типа данных в другой. Преобразование типа может выполняться в следующих случаях:
• присваивание или инициализация переменной значением другого
типа данных;
• передача значения в функцию, где тип параметра – другой;
• возврат из функции, где тип возвращаемого значения – другой;
• использование бинарного оператора с операндами разных типов.
В C++ различают явное и неявное преобразование типов данных.
Неявное преобразование типов данных выполняет компилятор С++, а явное выполняет сам программист.
7.4. Неявное преобразование типа
Неявное преобразование типов данных (или ещё «автоматическое
преобразование типа») выполняется всякий раз, когда требуется один фундаментальный тип данных, а предоставляется другой, и пользователь не
указывает компилятору, как выполнить конвертацию (т.е. не использует явное преобразование типов через операторы casts).
Существует два основных типа неявного преобразования типов:
• числовое расширение;
• числовая конверсия.

7. Типы данных
42
7.5. Числовое расширение
Когда значение из одного типа данных конвертируется в другой тип
данных побольше (по размеру и по диапазону значений), то это называется
числовым расширением. Например, int может быть расширен в long, а float
может быть расширен в double.
В C++ есть два типа расширений:
• Интегральное расширение (или ещё «целочисленное расшире-
ние»). Включает в себя преобразование целочисленных типов, меньших,
чем int (bool, char, unsigned char, signed char, unsigned short, signed short) в
int (если это возможно) или unsigned int.
• Расширение типа с плавающей точкой. Конвертация из float в double.
Интегральное расширение и расширение типа с плавающей точкой
используются для преобразования «меньших по размеру» типов данных в
типы int/unsigned int или double (они наиболее эффективны для выполнения
разных операций).
7.6. Числовая конверсия
Когда конвертируется значение из более крупного типа данных в
аналогичный, но более мелкий тип данных, или конвертация происходит
между разными типами данных, то это называется числовой конверсией.
7.7. Обработка арифметических выражений
При обработке выражений компилятор разбивает каждое выражение
на отдельные подвыражения. Арифметические операторы требуют, чтобы
их операнды были одного типа данных. Чтобы это гарантировать, компилятор использует следующие правила:
Если операндом является целое число меньше (по размеру/диапазону) типа int, то оно подвергается интегральному расширению в int или в
unsigned int.
Если операнды разных типов данных, то компилятор вычисляет операнд с наивысшим приоритетом и неявно конвертирует тип другого операнда в соответствие к типу первого.

7.9. Явное преобразование типов данных
43
7.8. Приоритет типов операндов:
long double (самый высокий);
double;
float;
unsigned long long;
long long;
unsigned long;
long;
unsigned int;
int (самый низкий).
Чтобы узнать решающий тип в выражении, можно использо-
вать оператор typeid(), который находится в заголовочном файле typeinfo.
7.9. Явное преобразование типов данных
В C++ есть 5 типов операторов casts (или ещё «операторов явного
преобразования типов»):
C-style cast;
static_cast;
const_cast;
dynamic_cast;
reinterpret_cast.
Оператор static_cast лучше всего использовать для конвертации од-
ного фундаментального типа данных в другой. Преимуществом static_cast
перед оператором C-style cast является проверка его компилятором во
время компиляции, что усложняет возможность возникновения непреднамеренных проблем, таких как изменение константы.
Практическое задание 3. Преобразование типов данных
Задание: выполнить проверку соответствия чисел заданному фор-
мату (максимальное значение должно быть вычислено программно). Выполнить указанные операции по вариантам. Для вариантов с вещественными числами выполнить неявное преобразование в тип int. Для вариантов
целыми числами выполнить явное преобразование в тип float. Числа вводятся пользователем с клавиатуры.

7. Типы данных
44
Таблица 19
Варианты для практического задания 3
№
вар.
Входные данные
Представление выходных данных
1
2 числа longlong. Операция умножения
Вывести числа в шестнадцатеричной системе счисления
Все числа записываются через пробел, если
длина полученной строки больше 15 символов, выполнить перенос на новую строку
2
4 числа unsignedshort.
Операция сложения инкрементов чисел
После цифры 5 выполнять вертикальную
табуляцию
3
3 числа unsignedint. Операция получения остатка
от деления
Максимальное количество символов: 25
Вывести число в 8-СИ. Если его длина превышает 25 символов, то необходимо вывести 25 первых символов числа
4
2 числа int. Операция сложения декрементов чисел
В полученной строке все цифры 4 выводить
в апострофах.
Пример: 0x0”4”21
5
3 числа float. Операция
получения целой части от
деления
Все числа записываются через пробел, если
длина полученной строки больше 10 символов, выполнить перенос на новую строку
6
4 числа unsignedint. Операция получения остатка
от деления
Максимальное количество символов: 20
7
2 числа unsignedshort.
Вывести меньшее из чисел
Вывести 10 чисел, остальные отбросить
8
3 числа longdouble. Операция деления
В полученной строке все цифры 8 выводить
на экран в апострофах
9
2 числа float. Операция де-
ления
Показать знак для положительных чисел
10
2 числа double. Операция
сложения инкрементов чисел
После каждой цифры 2 выполнять вертикальную табуляцию
11
3 числа unsignedlonglong.
Операция сложения декрементов чисел
Вывести первые 15 чисел, остальные отбросить

7.9. Явное преобразование типов данных
45
Окончание табл. 19
№
вар.
Входные данные
Представление выходных данных
12
2 числа int. Вывести число,
наибольшее по модулю
Вывести 30, остальные отбросить
13
2 числа usignedint. Выве-
сти большее из чисел
Каждые 20 символов выполнять перенос
строки
14
4 числа float. Вывести
меньшее из чисел
Вывести числа, больше чем А
15
2 числа double. Операция
деления
После каждой цифры 9 выполнять верти-
кальную табуляцию

7. Типы данных
46
8. ПОРАЗРЯДНАЯ ОБРАБОТКА ДАННЫХ
Кроме арифметических операций в языке С++ допускается выполнять поразрядные логические операции. Поразрядными они называются
потому, что реализуются над соответствующими двоичными разрядами
независимо.
В табл. 20 показан пример программного кода выполнения логического И и ИЛИ над целыми числами.
Таблица 20
Поразрядные операции над числами
int N,M,R;
N=16; /*0x0010;*/
M=15; /*0x000f;*/
R=N&M;
Name
Value
N
16
M
15 R 0
int N,M,R;
N=16; /*0x0010;*/
M=15; /*0x000f;*/
R=N|M;
Name
Value
N
16 M 15
R
31
Поразрядные операции применяют для реализации алгоритмов
«низкого» уровня. Например, для управления оборудованием либо обмена
информацией по последовательным каналам связи. Чаще всего в подобных
алгоритмах необходимо выделить содержимое определенных групп зарядов и установить их в нужное значение.
Операция логического И используется для маскирования отдельных
разрядов, т.е. в выделении содержимого нужного набора разрядов.
Маска – двоичное число, которое содержит единицы в позициях выделяемых разрядов. В табл. 21 показано, как программно выполнить маскирование разрядов. Комментарий содержит шестнадцатеричное представление значений переменных.
Таблица 21
Маскирование разрядов
int N,M,R;
N=2226; /*0x08b2;*/
M=48; /*0x0030;*/
R=N&M;
Name
Value
N
226
M
48 R 48

8. Поразрядная обработка данных
47
После логического умножения на маску образуется результат. Срав-
нивая его с заранее рассчитанными величинами, реализуют программную
логику выработки результата.
Операции сдвига разрядов применяются для анализа и преобразова-
ния отдельных групп разрядов. С арифметической точки зрения сдвиг
вправо равносилен делению на 2, а сдвиг влево – умножению числа на 2.
В табл. 22 показано, как полученный маскированием результат мо-
жет сдвигаться вправо.
Таблица 22
Сдвиг разрядов
int N,M,R;
N=2226; /*0x08b2;*/
M=48; /*0x0030;*/
R=N&M;
R=R>>4;
Name
Value
N
226 M 48
R
3
Сравнивая результаты примеров маскирования и сдвига разрядов в
табл. 21 и 22, видно, что сдвиг на 4 разряда вправо эквивалентен делению
на 16. Проведение подобных аналогий полезно при программировании алгоритмов поразрядной обработки.
В табл. 23 приведен пример программного кода шифрования и де-
шифрования строки символов.
В первом примере результатом выполнения программы будет за-
шифрованный код. В примере 2 получим уже дешифрованную строку.
Таблица 23
Пример шифрования и дешифрования
char Str[]=" Совершенно секретно!!!";
char Key[]=ncafkgfkghagkaglgkgkjgl1hrktu";
char Res[100];
int ;
//кодирование
for(int i=0; i<sizeof(Str)/sizeof(char);i++0
Res[i]=Str[i]^Key[i];
char Str[]=" Совершенно секретно!!!";
char Key[]=ncafkgfkghagkaglgkgkjgl1hrktu";
char Res[100];

8. Поразрядная обработка данных
48
Окончание табл. 23
int ;
//кодирование
for(int i=0; i<sizeof(Str)/sizeof(char);i++0
Res[i]=Str[i]^Key[i];
// декодирование
for(int i=0; i<sizeof(Str)/sizeof(char);i++0
Res[i]=Res[i]^Key[i];
Шифрование основано на использовании поразрядной операции
суммирования по модулю 2. Для шифрования на исходную строку «накладывается» случайная последовательность символов. Наложение последовательности – это поразрядное суммирование. Если на зашифрованную
строку наложить ту же случайную последовательность, выполнится дешифрование (табл. 23).
8.1. Шифрование матриц
В примере в табл. 24 к каждому элементу добавляется ключ, а на его
место записывает остаток от деления суммы ключа и значения элемента
на 10. Таким образом получается зашифрованная матрица.
Таблица 24
Пример шифрования и дешифрования матрицы
int key; //ключ
int array[N]; // массив
for(int i = 0; i < N; i++) // цикл шифрования
{
array[i] = ((array[i] + key) % 10);
}
for (int i = 0; i < N; i++) // цикл расшифровки
{
array[i] = (((array[i] +10) - key) % 10);
}
Для расшифровки к элементу прибавляется 10 (чтобы исключить отрицательные значения), вычитается ключ и записывается остаток от деления на 10. Алфавит для данного примера – цифры.

8.2. Шифр Вернама
49
8.2. Шифр Вернама
Шифр является разновидностью криптосистемы одноразовых блок-
нотов.
Таблица 25
Пример шифрования Вернама
void shifr_Vernam
{
int i,len; //Определяем необходимые переменные
len = strlen("Holo word!");// определяем длину строки открытого
текста
char *oStr = new char[len]; //объявляем динамический массив ука-
занной длины для открытого текста
char *key = new char[len]; //точно такой же массив объявляем для
ключа
char *shStr = new char[len]; //массив-приемник для зашифрован-
ного текста
oStr="Hello.\, word!"; //помещаем в массив открытый текст
// определяем ключ случайным образом
for(i = 0; i < len; i++)
key[i]=(char)rand()%255;
//собственно само шифрование
for(i = 0; i < len; i++)
shStr[i]=oStr[i]^key[i];
//для наглядности выведем на экран результат работы
printf("\nOtkrytyi text: %s", oStr);
printf("\nZashifrovanyi text: %s", shStr);
}

8. Поразрядная обработка данных
50
9. УКАЗАТЕЛИ
Указатель – производный тип, позволяющий хранить адреса памяти,
в которых размещена переменная. Указатель имеет тип, тип указателя
определяется соответственно синтаксису языка С++.
Например, выражение char *PM объявляет указатель, здесь PM –
указатель символьного типа. Он может хранить только адреса символов, но
не сами символы.
Поскольку символьные массивы, как и любые другие массивы, размещаются в памяти последовательно, обращаться к массиву можно по адресу его первого элемента, т.е. по указателю. Чтобы указатель принял значение адреса переменной, используется операция разыменования &.
Например, выражение
PM = &M[0];
означает, что указатель PM получает адрес нулевого элемента массива. Выражение
*PM=’A’;
означает, что в память по адресу из PM будет записано значение символа А. Операция * перед именем указателя означает операцию над содержимым памяти, на которую указывает указатель.
Над значениями указателя допустимы операции целочисленной
арифметики. Программный код в табл. 26 иллюстрирует основные возможности по изменению значений переменных через указатель. Справа показана информация отладчика: 32-разрядный адрес массива и значения его
элементов после выполнения программного кода.
Важно подчеркнуть, что тип указателя определяется независимо и,
по сути, создает возможность различной интерпретации содержимого памяти. В табл. 27 приведен пример того, как указатель на целочисленный
массив может быть преобразован в символьный тип. После этого преобразования с областью памяти, содержащей два 16-разрядных целых, оперируют как с последовательностью четырех однобайтовых символов.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
