Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Основы разработки программ на языке С++ для систем информационной безопасности. Учебное пособие

.pdf
Скачиваний:
1
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
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-разрядных целых, опери­руют как с последовательностью четырех однобайтовых символов.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]