Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Информация об ошибках системной функции

Проблемой, почти никогда не возникающей вне использования системных средств, является сама принципиальная выполнимость вызываемой функции. Когда в прикладном программировании задается управляющая конструкция или выражение, то заданные ими действия всегда выполняются по заложенным в них правилам. При обращении же к системным функциям возможные ситуации не столь однозначны. Чтобы их понять, достаточно вспомнить работу с файлами в прикладном программировании (работа с файлом, по существу, неизбежно требует использования средств именно операционной системы). При семантически верном задании открытия файла, он может быть и не открыт, например, когда для чтения открывают файл, который не существует. Значительная часть системных функций совсем не обязательно обеспечивает запращиваемое действие! Поэтому в API вводятся вспомогательные средства, позволяющие программе обнаружить, выполнилось ли в действительности запрашиваемое действие.

Наиболее традиционно эта проблема решается в Unix. Большинство системных функций Unix имеют вид

int имяфункции (список_аргументов),

возвращая в качестве основного значения целое число. Это число может нести значение, определяющее результат действия функции, но одно из значений (обычно ‑1), зарезервировано за условным кодом ошибки. В описании системной функции обязательно присутствует информация, описывающая ошибочные ситуации, которые могут возникать при выполнении функции, и соответствующие им значения кода возврата (возвращаемого значения). Описание кодов ошибочных ситуаций в Unix совершенно обязательно в справочной информации по любой системной функции.

Заметим, что само получение справочной информации по некоторой системной функции в Unix вызывается командой man текстового режима. Эта команда является сокращением слова manual и задается в виде

man имяфункции

Если по такому вызову появится информация об одноименной команде, то следует использовать вызов справки в форме

man 2 имяфункции

Справочная информация появляется в текстовом окне консоли и имеет несколько архаичный вид (без возможности использования гипертекста).

Другой формой контроля ошибок в Unix является специальная переменная
errno. Для основных функций операционной системы Unix код ошибки неявно заносится в эту специальную глобальную переменную, описанную в заголовочном файле errno.h. Такой прием дает принципиальную возможность анализировать значение этой переменной после обращения к системной функции. Но делать это следует сразу же после системного вызова, так как следующий системный вызов, в свою очередь, изменяет эту переменную.

Практическое использование значений переменной ошибок errno достигается с помощью вспомогательных функций perror() и strerror(). Первая из них имеет прототип

void perror(const char *s),

а вторая имеет прототип

char *strerror(int errnum).

Вторая функция возвращает указатель на текст, описывающий ошибку, а первая непосредственно отображает в стандартном потоке ошибок этот текст, причем предваряемый любой пользовательской текстовой информацией, которая содержится в аргументе s. Заметим, что к настоящему моменту в операционной системе Linux имеется более двухсот кодов ошибок, которые отображаются этими функциями. Следует также отметить, что указанные функции могут использоваться для локальной диагностики ошибок и в других операционных системах, а именно для программ, написанных на языке С. Такая возможность имеется даже в MS DOS, она присутствует и в OS/2, и в Windows. Но во всех этих последних ОС такая возможность является вспомогательной и не гарантируется для всех системных функций, которые используют свои собственные способы самодиагностики. (В MS DOS и Windows функции, основанные на глобальной переменной errno, позволяют определить только около 50 типов ошибок).

В операционной системе OS/2 системные функции делились на несколько функциональных групп, определяемых префиксом их имени. Основные функции имеют имена вида Dos Собственноеимя. Функции обслуживания дисплея (видеосистемы) имели имена вида Vio Собственноеимя, для обслуживания клавиатуры использовались функции с именами Kbd Собственноеимя, а для обслуживания мыши – с именами Mou Собственноеимя.

Все основные системные функции возвращали в этой ОС в качестве основного значения функции величину типа APIRET, а функции видеосистемы, клавиатуры и мыши – типа APIRET16. Принято строгое правило, что нулевое значение кода возврата однозначно определяет безошибочное выполнение системной функции. Все иные значения типа APIRET и APIRET16 дают код ошибки. Коды ошибки были описаны в заголовочном файле

bseerrs.h

систем программирования для OS/2, а их описание приведено в одном из файлов справочной системы. Обязательным в этой справочной системе являлось приведение всех возможных кодов ошибки с соответствующими комментариями. Отдельным пунктом справочной подсистемы, являлся пункт с наименованием Errors, которые содержал удобное для программиста соотнесение номеров кодов ошибок их содержательному толкованию.

Наиболее экзотической является получение информации об ошибках в MS Windows. Во первых, отсутствует какое-либо подобие систематичности в системных функциях. Возвращаемые значения системных функций могут быть описаны как VOID, BOOL, HANDLE, PVOID, LONG или DWORD. При использовании типа BOOL возвращаемое значение 0 обозначает ситуацию ошибки (категорически не рекомендуется [13] проверять это значение на TRUE). При типах HANDLE, LONG или DWORD ситуацию ошибки дает значение -1 или 0 в зависимости от конкретной функции. Функции с возвращаемым значением PVOID индицируют ошибку значением NULL.

Для получения же собственно кода ошибки в MS Windows программисту приходится принимать немалые дополнительные усилия. Если по возвращаемому значению системной функции определяется, что ошибка есть, следует немедленно вызывать специальную функцию GetLastError(), которая не имеет аргументов и возвращает значение типа DWORD. Функция GetLastError() возвращает последнюю ошибку, возникшую в ходе выполнения программы (точнее нити программы). Именно это 32-битное значение дает код ошибки. Собственно коды ошибок, общие для всех системных функций, содержатся в заголовочном файле WinError.h.

Отличительной и не очень приятной особенностью MS Windows является отсутствие информации о возможных кодах ошибки для конкретных функций. Известный специалист и один из редакторов журнала "Microsoft Systems Journal" Дж. Рихтер в книге [13] пишет буквально следующее: "Время от времени меня кто-нибудь да спрашивает, составит ли Microsoft полный список кодов всех ошибок, возможных в каждой функции Windows. Ответ: увы, нет. Скажу больше, такого списка никогда не будет – слишком уж сложно его составлять и поддерживать для все новых и новых версий системы. Проблема с подобным списком еще и в том, что вы вызываете одну API-функцию, а она может обратиться к другой, та – к третьей и т.д. Любая из этих функций может завершиться неудачно (и по самым различным причинам). Иногда функция более высокого уровня сама справляется с ошибкой в одной из вызванных ею функций и в конечном счете выполняет то, что Вы от нее хотели. В общем, для создания такого списка Microsoft пришлось бы проследить цепочки вызовов в каждой функции, что очень трудно. А с появлением новой версии системы эти цепочки нужно было бы пересматривать заново."

Числовые коды ошибок, возвращаемые функцией GetLastError(), достаточно сложно для разработчика соотнести с наименованием ошибки. Если требуется распознавание вида ошибки при автоматическом выполнении программы, то разработчики этой ОС предлагают для использования специальную функцию FormatMessage.

В конечном счете эта функция делает почти то же самое, что и функция strerror в Unix, но сложность использования функции FormatMessage неизмеримо больше. Прежде всего она имеет прототип

DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource,

DWORD dwMessageId, DWORD dwLanguageId,

LPTSTR lpBuffer, DWORD nSize, va_list *Arguments).

Здесь не будет рассматриваться все многообразие ее возможностей, которые в большинстве ситуаций излишни (от функции требуется лишь выдать текст, называющий причину ошибки). Главным по значению является третий ее аргумент dwMessageId, который и задает распознаваемый код ошибки. Если не использовать "хитрых" возможностей динамического выделения памяти под буфер текста, то адрес буфера для текста задается в аргументе lpBuffer, а его размер в аргументе nSize. Важным в применении является и первый аргумент, который дает возможность использовать не только системные, но и пользовательские коды ошибок. Для системных ошибок в аргументе dwFlags должно присутствовать логическое слагаемое FORMAT_MESSAGE_FROM_SYSTEM. Мощные потен­циаль­ные возможности заложены в аргументе dwLanguageId, призванном обеспечить многоязыковую поддержку сообщений, но к настоящему моменту для России работающим является только простейшей вариант языка по умолчанию. (В Windows 9x неправильно функционирует даже вариант, принудительно запраши­ваю­щий англоязычный американский текст.) Работающий вариант задается макросом MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT). Оставшиеся без рассмотрения аргументы следует брать нулевыми. В результате типовой вызов данной функции имеет вид

len=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,

NULL, k, // k - номер ошибки, возвращенный функцией GetLastError()

MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

txtmess, sizeof(txtmess), NULL);

где имя txtmess определено предварительно в описании вида char txtmess[300]. Возвращаемое функцией значение дает число символов в тексте, сформированном ею в заданном буфере.

Функция FormatMessage обладает возможностью возвращать порядка тысячи различных наименований ошибок на языке текущей локализации (т.е. при использовании русифицированной версии Windows – на русском языке). Заметим кстати, что в более точных терминах программный интерфейс MS Windows называется Win32. Существенной особенностью рассматриваемой функции оказывается использование возвращаемых текстов сообщений об ошибках, представленных в кодировке для графического режима. Исторически сложилось так, что тексты, записанные не с помощью латинского алфавита, имеют различное представления в графическом и текстовом режиме. (Для англоязычных стран и пользователей эта особенность совершенно незаметна и часто может быть даже неизвестной.)

Для других стран профессиональное использование программирования для ОС типа Windows требует учета указанной особенности. Решение возникающих при этом проблем обеспечивается парой функций преобразования из одной формы представления в другую. Эти функции задаются упрощенными прототипами

BOOL CharToOem(char *textsource, char *textresult),

BOOL OemToChar(char *textsource, char *textresult).

При использовании указанных функций следует иметь в виду, что разработчики условным буквосочетанием Char в названии функций обозначают кодировку графического режима, а обозначением Oem в названии – кодировку текстового режима. Таким образом функция CharToOem задает преобразование текста из кодировки графического режима Windows в текстовый режим, а функция OemToChar – преобразование текста из кодировки текстового режима в графический режим.

Наиболее совершенные средства обработки ошибок были заложены в OS/2, но рассматривать мы их не будем.

 

<== предыдущая лекция | следующая лекция ==>
Командный интерфейс пользователя в ОС | Понятия дескрипторов, идентификаторов и хэндлов
Поделиться с друзьями:


Дата добавления: 2014-01-05; Просмотров: 416; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.012 сек.