Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Основы разработки программного обеспечения на примере языка С. Учебное пособие для СПО
.pdf
Функция decToHex преобразует десятичную цифру в
шестнадцатеричную.
char decToHex(unsigned char val)
{
if ( (val >= 0) && (val <= 9) )
{
return (char)(val + (unsigned char)'0');
} else
{
if ( (val >= 10) && (val <= 15) )
{
return (char)(val + (unsigned char)'A' - 10);
} else
{ return 0; }
}
}
Деление десятичного числа на 16 дает первый разряд
шестнадцатеричного числа, а остаток от деления - второй. Отметим,
что в выходную строку записывается не текущий получаемый выходной
байт (tmpVal2), а предыдущий - tmpVal1, так как к нему в старшие
биты уже добавлены биты следующего входного символа (получаемые
как curNum << (8 - shift)). Поэтому после прохождения всей входной
строки в цикле while (i < len) {...} в переменной tmpVal2
остается последний формируемый выходной символ, который в конце
цикла записывается в tmpVal1. Его приходится дополнительно
кодировать в шестнадцатеричное представление после завершения
цикла:
res[j] = decToHex(tmpVal1 / 16);
res[j + 1] = decToHex(tmpVal1 % 16);
res[j + 2] = '\0';
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
201

В конец строки согласно правилам представления строки в языке Си
дописывается символ '\0 '.
Теперь рассмотрим функцию декодирования сообщения
decodeFromPDU:
void decodeFromPDU(char *str, char *res)
{
int len;
int i, j;
int shift;
unsigned char prevNum, d1, d2, curNum, curRes;
j = 0;
len = length(str);
i = 1;
prevNum = 0;
while(str[i-1])
{
if(str[i])
{
d1 = hexToDec(str[i-1]);
d2 = hexToDec(str[i]);
curNum = d1*16 + d2;
shift = ((((i + 1) / 2)-1) % 7);
if(((shift) == 0)&&(i>1))
{
prevNum = prevNum & 127;
res[j++] = prevNum;
/* special code for symbol @ */
if (res[(j-1)] == 0)
{res[(j-1)] = (unsigned char)'@';}
prevNum = (curNum >> (7 - shift));
}
curRes = (curNum << shift) + prevNum;
curRes = curRes & 127;
res[j++] = curRes;
/* special code for symbol @ */
if (res[(j-1)] == 0)
{res[(j-1)] = (unsigned char)'@';}
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
202

prevNum = (curNum >> (7 - shift));
} else
{
break;
}
i+=2;
}
if(shift == 6)
{
prevNum = prevNum & 127;
/* special code for symbol @ */
if (res[(j-1)] == 0) {res[(j-1)] = (unsigned char)'@';}
res[j++] = prevNum;
}
res[j] = '\0';
}
Она также последовательно движется по входной строке str, в которой
закодированный текст SMS-сообщения представлен в
шестнадцатеричном текстовом виде.
Поэтому шаг равен двум (на каждой итерации цикла прохода по строке
str выполняется i+=2) и очередные два символа переводятся в один
байт кода SMS:
d1 = hexToDec(str[i-1]);
d2 = hexToDec(str[i]);
curNum = d1*16 + d2;
Функция hexToDec переводит шестнадцатеричную текстовую цифру в
десятичное число:
unsigned char hexToDec(char hexDigit)
{
if ((hexDigit >= '0') && (hexDigit <= '9'))
{
return (unsigned char)hexDigit - (unsigned char)'0';
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
203

} else
{
if ((hexDigit >= 'A') && (hexDigit <= 'F'))
{
return (unsigned char)hexDigit (unsigned char)'A' + 10;
} else
{
return 0;
}
}
}
Далее рассчитывается сдвиг, на который в текущем кодированном байте
сдвинут код текущего символа: shift =( (((i + 1) / 2) -1)
% 7);
Здесь ((i + 1) / 2) дает номер входного байта (i - это счетчик
шестнадцатеричных символов, начинающийся с 0, на каждый входной
кодированный байт занято две шестнадцатеричные цифры).
На первом шаге (i=1) сдвиг равен нулю, на втором он равен 1, для 7-го
входного кодированного байта (i=13) сдвиг равен 6. Для 8-го входного
байта сдвиг снова равен 0, так как в его 7-ми младших байтах
полностью содержится 9-й выходной символ. А 8-й выходной символ
хранится в 7-ми старших битах 7-го входного байта.
На каждом 7-м входном байте, для которого сдвиг оказывается равен 0,
надо сделать двойную обработку - "вынуть" символ из предыдущего
байта с учетом одного бита из текущего байта и "вынуть" символ из
текущего байта, для чего дополнительно выполняется следующий код:
if(((shift) == 0)&&(i>1))
{
prevNum = prevNum & 127;
res[j++] = prevNum;
/* special code for symbol @ */
if (res[(j-1)] == 0)
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
204

{res[(j-1)] = (unsigned char)'@';}
prevNum = (curNum >> (7 - shift));
}
Следует отметить, что если количество байт кода кратно восьми, то на
последнем шаге обрабатывается лишь один младший бит последнего
байта кода, а сдвиг равен шести. "Вынимание" последнего
закодированного символа (из первых семи бит последнего байта кода)
по алгоритму выполняется отдельно, поэтому надо после цикла
сформировать последний символ:
if(shift == 6)
{
prevNum = prevNum & 127;
/* special code for symbol @ */
if (res[(j-1)] == 0)
{res[(j-1)] = (unsigned char)'@';}
res[j++] = prevNum;
}
res[j] = '\0';
В GSM кодировка символов определяется стандартом GSM 03.38 и
несколько отличается от стандартной таблицы ASCII. В частности,
символ '@' имеет нулевой код и совпадает с кодом конца строки в языке
Си. Из-за этого в приведенном примере символ с кодом '\0' заменяется
символом '@':
if (res[ (j-1)] == 0) {res[ (j-1)] = (unsigned char)'@';}
А при работе с кодировкой GSM 03.38 на языке Си необходимо знать
длину строки, иначе в случае восьми символов текста, в которых
последний символ равен '@', последний значащий байт строки равен
нулю, что соответствует символу конца строки, и он не будет корректно
обрабатываться стандартными функциями как значащий.
В случае когда необходимо передать символы, отсутствующие в GSM
03.38, используется Unicode, в котором один символ кодируется двумя
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
205

байтами. В Unicode можно хранить сразу несколько алфавитов, но в этом
случае 140 байт вмещают лишь 70 символов текста. Поэтому если в
SMS-сообщении содержатся русские буквы (которых нет в таблице GSM
03.38), то оно кодируется в формате Unicode и содержит максимум 70
символов. Если же использовать только английский алфавит, то, как уже
было показано, в сообщении можно использовать целых 160 символов!
Вопросы и задачи для самостоятельного решения
Придумайте и опишите протокол общения двух программ при
игре "Морской бой". Предусмотрите упаковку координат (X, Y) на
поле боя в один байт 16-битовой команды протокола.
Реализуйте программу кодирования (шифрования) и
декодирования сообщения по алгоритму Цезаря (каждая буква
сообщения заменяется на другую букву алфавита, циклически
сдвинутую на позицию буквы ключа).
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
206

Приложения
При изучении наук примеры полезнее правил.
Исаак Ньютон
Приложение А. Спецификация и ее структура
1. Общее описание.
Раздел, содержащий краткую характеристику программной единицы
разработки (назначение, краткое описание, ограничения реализации).
2. Описание интерфейса.
Раздел, содержащий описание правил, форматов взаимодействия
программы с внешним миром. В тех случаях, когда специфицируется
программный модуль с несколькими вызываемыми процедурами,
описания входа, выхода, хранимых данных могут повторяться для
каждой компоненты.
2.1. Входные данные.
2.1.1. Данные, вводимые пользователем с клавиатуры.
В разделе описываются форматы входных строк данных, получаемых от
пользователя. Возможно включение текстов приглашающих сообщений
из раздела 2.2.1.
2.1.2. Параметры - данные, передаваемые из среды ОС.
В разделе описывается формат данных командной строки, передаваемой
из среды операционной системы при вызове программы.
2.1.3. Хранимые данные.
Раздел описывает форматы данных на внешних носителях, может быть
вынесен в пункт 2.3.
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
207

2.1.4. Информационное окружение до начала работы.
Раздел описывает структуру носителей данных директории, файлы,
ограничения доступа и может быть вынесен в пункт 2.3.
2.2. Выходные данные.
2.2.1. Сообщения программы.
Форматы выходных строк сообщений на терминал пользователя.
Желательно сопровождать комментариями, отражающими причину
вывода сообщения.
2.2.2. Результаты вычисления.
Форматы вывода основных результатов работы программы: количество
строк, позиционирование, точность представления и пр.
2.2.3. Хранимые данные.
Раздел описывает форматы данных на внешних носителях, может быть
вынесен в пункт 2.3.
2.2.4. Информационное окружение после завершения работы.
Раздел описывает структуру носителей данных директории, файлы,
ограничения доступа, сформированные в процессе работы программы,
и может быть вынесен в пункт 2.3.
2.3. Хранимые данные (в файлах на внешних носителях).
Раздел может отсутствовать, если все было соотнесено со входом и
выходом.
2.3.1. Общая структура информационного окружения.
В разделе описывается структура носителей, директорий.
2.3.2. Свойства файлов (наборов данных).
В разделе описываются свойства файлов, ограничения доступа, правила
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
208

создания/уничтожения.
2.3.3. Форматы записей.
В разделе описываются форматы записей файлов, сведения об их
упорядоченности, свойствах полей.
3. Функциональные требования.
Раздел содержит структурированный список требований. Первый
способ: структура требований ориентирована на декомпозицию
функций программы (ввод, вывод, контроль данных, расчет параметров,
вычисление результата и т.п.). Второй способ ориентирован на процедурное описание требований. То есть производится описание того,
как должна действовать программа.
Каждое требование должно иметь свой уникальный номер 3.1., 3.1.1. и
иметь вид:
Программа должна проверить, что если ... то ...
4. Тест-требования.
Раздел содержит описание того, что надо проверить, для того, чтобы
убедиться, что соответствующая функциональность присутствует в
программной реализации.
Каждое требование должно иметь свой уникальный номер 4.1., 4.1.1. и
иметь вид:
Проверить, что ...
5. Реализация.
Проект реализации.
Код программы.
Дополнительные тест-требования.
В разделе описываются свойства, определяемые спецификой
реализации.
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
209

6. Тест-план.
Тест-план - программа действий, направленных на то, чтобы убедиться,
что все требования к программе выполняются и проверены. Обычно
имеет формат таблицы с полями:
порядковый номер теста,
проверяемые требования,
исходные данные,
ожидаемый результат,
комментарий к сути проверяемого свойства.
Часто совмещают в одной таблице и тест-план, и протокол выполнения
тестов, добавляя поле фактического результата.
Тест-план должен проверять реальную работу алгоритма при заданных
требованиями входных воздействиях и поведение программы во
внештатных ситуациях.
7. Отчет о прогоне тестов.
Результаты выполнения тестов.
Приложение Б. Пример шапки документа – таблицы
изменений
Дата Версия
Автор
изменений
Изменения
22.11.05 1.0.0
Амосов
П.А.
Созданы пункты 1–4
29.11.05 1.0.1
Амосов
П.А.
Добавлен метод расчета длины int len()
02.11.05 1.0.1
Хлытчиев
О.И.
Ревью, изменить п. 3: уточнить требования
для случая отсутствия параметров
Основы разработки программного обеспечения на примере языка СС.В. Синицын, О.И. Хлытчиев
210
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
