Программирование >>  Структура ядра и системные вызовы 

[ 1 ] 2 3 4 ... 98


Структура ядра, системные-вызовы

Операционная система UNIX и стандарты ANSI

Теренс Чан ведет курсы по передовым методам программирования и новейшим средствам разработки программного обеспечения для ОС UNIX при университете штата Калифорния в Беркли и Санта-Крузе. За его плечами более чем двенадцатилетний практический опыт проектирования и разработки крупномасштабных программ на С++ и С для всех основных UNIX-платформ. В настоящее время Теренс Чан является консультантом по проектированию объектно-ориентированных, распределенных и многопоточных приложений архитектуры клиент/сервер.

Операционная система UNIX была создана в конце 60-х годов, и с тех пор появилось множество различных ее версий для разных компьютерных систем. Последние версии системы UNIX развились из AT&T System V и BSD 4.x UNIX. Многие производители компьютеров добавляли к этим разновидностям UNIX собственные расширения, создавая таким образом новые версии UNIX. В конце 80-х годов AT&T и Sun Microsystems работали над совместным проектом по созданию UNIX System V release 4, который был, по сути, попыткой разработать стандарт на UNIX для компьютерной индустрии. Попытка эта оказалась не совсем успешной, поэтому UNIX System V.4 сегодня используют лишь немногие производители компьютеров.

Тем не менее в конце 80-х годов несколько организаций предложили ряд стандартов на UNIX-подобную операционную систему и среду программирования на языке С. Эти стандарты построены в основном на UNIX и не влекут за собой существенных изменений в системах, выпускаемых фирмами-производителями, что облегчает их практическое внедрение. Два из этих стандартов, ANSI С и POSIX (Portable Operating System Interface - интерфейс переносимых операционных систем), разработаны Американским национальным институтом стандартов (ANSI) и Институтом инженеров по электротехнике и радиоэлектронике (ШЕЕ). Эти организации имеют очень большое влияние на разработку стандартов для данной отрасли - большинство производителей компьютеров сегодня предлагают UNIX-системы, соответствующие стандартам ANSI С и POSIX.l (последний представляет собой подмножество стандартов POSIX).

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



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

Более того, даже некоторые общие API могут быть в разных UNIX-системах реализованы по-разному (например, API fcntl в UNIX System V может использоваться для блокировки и освобождения файлов, а в BSD UNIX он такой способностью не обладает). Стандарты ANSI С и POSIX требуют, чтобы все соответствующие им системы содержали одинаковый набор стандартных библиотек и системных API; эти стандарты определяют также сигнатуры (тип данных, число аргументов, возвращаемое значение) и порядок работы этих функций во всех системах. Таким способом добиваются того, что программы, которые используют эти функции, можно переносить на другие системы, соответствующие данным стандартам.

Большинство функций, определенных в этих стандартах, представляют собой подмножество функций, имеющихся в большинстве UNIX-систем. Комитеты ANSI С и POSIX все же предложили ряд функций собственной разработки, но эти функции лишь привносят дополнительные неоднозначность и неопределенность в некоторые существующие версии UNIX. Опытный разработчик, имеющий дело с UNIX и С, легко разберется в упомянутых стандартах. Поддержка этих стандартов производителями компьютеров - тоже несложная задача.

Цель данной книги - познакомить пользователей с новейшими методами программирования для UNIX-систем, в том числе научить их писать переносимые и легко сопровождаемые коды. Для обеспечения второго пункта сформулированной цели нужно ознакомить пользователей с функциями, определенными в различных стандартах, и с функциями, имеющимися в ОС UNIX. Лишь при этом условии пользователи смогут сделать разумный выбор в пользу тех или иных функций и API.

Далее в этой главе дается обзор стандарта ANSI С, проекта стандарта ANSI/ISO С++ и стандартов POSIX. В следующих главах более подробно описываются функции API, определенные в этих стандартах, а также функции API ОС UNIX.

1.1. Стандарт ANSI С

в 1989 году Американский национальный институт стандартов (ANSI) предложил стандарт языка программирования С (ХЗ. 158-1989), целью которого была стандартизация конструкций и библиотек этого языка. Названный стандарт, широко известный как стандарт ANSI С, стал попыткой унификации языка С, создания его реализации, поддерживаемой во всех компьютерных системах. Сегодня большинство поставщиков вычислительной

техники продолжают поддерживать стандартный набор конструкций и библиотек языка С, предложенный Б. Керниганом и Д. Ритчи (широко известен как К&КС),но пользователи могут за дополнительную плату инсталлировать инструментальный пакет программ ANSI С.

Ниже перечислены основные отличия ANSI С от K&R С:

наличие прототипов функций;

поддержка описателей типов данных const и volatile;

поддержка локализации, т.е. разработки программного обеспечения, отвечающего потребностям различных стран и культур;

возможность использовать указатели на функции без их разыменования.

Хотя основное внимание в этой книге уделяется методике программирования на С++, читатели все равно должны быть знакомы со стандартом ANSI С. Дело в том, что многие стандартные библиотечные функции С не охватываются стандартными классами С++, поэтому почти все программы на С++ вызывают одну или несколько стандартных библиотечных функций С (например, функцию strlen или функции, предназначенные для получения значения текущего времени суток). Кроме того, читатели, которые, возможно, уже начали переносить свои С-приложения на С++, найдут в данном разделе описание совпадающих конструкций этих двух языков и различий между ANSI С и С++. Это должно облегчить переход с языка ANSI С на С++.

В ANSI С принят используемый в С++ метод создания прототипов функций, согласно которому для определения и объявления функции необходимо указать ее имя, тип данных аргументов и тип возвращаемых значений. Прототипы функций позволяют компиляторам ANSI С проверять пользовательские программы на предмет наличия вызовов функций, которые получают неверное число аргументов или аргументы несовместимых типов. Таким образом устраняется наиболее серьезный недостаток компиляторов K&R С, заключающийся в том, что неверные вызовы функций в пользовательских программах на этапе компиляции часто не обнаруживаются, но при выполнении приводят к краху программ.

В следующем примере определяется функция foo, которая должна принимать два аргумента. Первый аргумент, fmt, имеет тип данных char*, а второй - тип данных double. Функция .о возвращает значение unsigned long:

unsigned long foo (char* fmt, double data) {

/* тело функции foo */

Для того чтобы объявить указанную функцию, пользователь просто берет приведенное выше определение, удаляет тело и заменяет его точкой с запятой:

unsigned long foo (char* fmt, double data);



Для функций, принимающих переменное число аргументов, в определениях и объявлениях в качестве последнего аргумента должно стоять многоточие:

int printf(const char* fmt, ...);

int printf(const char* fmt, ...) {

/* тело функции printf */

}

Ключевое слово const объявляет, что некоторые данные не подлежат изменению. Например, объявление приведенным выше прототипом функции аргумента fmt типа const char* означает, что функция printf не может изменять данные в массиве символов, который передается ей как фактическое значение аргумента fmt.

Ключевое слово volatile объявляет, что значения некоторых переменных могут изменяться неизвестным для компилятора образом, намекая алгоритму оптимизации компилятора на то, что избыточные операторы с объектами volatile уцалятъ нельзя. Например, в представленном ниже примере определяется переменная ioPort, которая содержит адрес порта ввода-вывода системы. Два оператора, следующие за определением, должны ожидать прибытия из порта ввода-вывода 2 байтов данных и сохранять только второй байт:

char get io() {

volatile char* io Port char ch = *io Port; ch = *io Port;

0x7777;

/* прочитать первый байт данных */ /* прочитать второй байт данных *,/

Если переменную io Port в этом примере не объявить как volatile, то при компиляции программы компилятор может удалить второй оператор ch = *io Port, так как он считается лишним при наличии первого.

Описатели типов данных const и volatile имеются и в С++.

Язык ANSI С поддерживает национальные алфавиты, допуская использование в программах символов расширенной кодировки. Для хранения одного такого символа требуется больше 1 байта. Эти символы применяются в тех странах, где набор ASCII не является стандартом. Например, для представления каждого символа корейского алфавита требуется по 2 байта. Кроме того, в ANSI С есть функция setlocale, которая позволяет пользователям задавать формат представления дат, денежных единиц и вещественных чисел. Например, в большинстве стран дата выводится в формате число/месяц/год, а в США - в формате месяц/число/год.

Вот прототип функции setlocale:

#include <locale,h> , char setiocale ( int category, const char* locale );

Прототип функции setlocale и возможные значения аргумента category объявляются в файле заголовков <IocaIe.h>. Значения category показывают, к какому типу (типам) выводимой информации будет применена новая локальная среда. Некоторые возможные значения этого аргумента приведены в таблице.

Значение аргумента category Объект влияния

CTYPE

Макросы, определяемые в файле <ctype.h>

TIME

Формат даты и времени, возвращаемых функциями strftime

.NUMERIC

Форматы представления чисел функциями printfм seanf

.MONETARY

Формат представления денежной единицы, возвращаемой функцией localeconv

Соответствует одновременному действию всех перечисленных значений

Возможное значение аргумента locale - это строка символов, которая определяет, какую локальную среду нужно использовать. Значения С, POSIX и en US соответствуют локальным средам UNIX, POSIX и US. По умолчанию все процессы в системе, на которую распространяется стандарт ANSI С или POSIX, выполняют во время запуска вызов, эквивалентный следующему:

setlocale( LC ALL, С );

Таким образом, все запускаемые процессы имеют известную локальную среду. Если аргумент locale имеет значение NULL, то функция setlocale возвращает текущее значение locale вызывающего процесса. Если аргумент locale имеет значение (пустая строка), то функция setlocale ищет значение этого аргумента в переменной среды LC ALL, в переменной среды с именем, совпадающим со значением аргумента category, и, наконец, в переменной среды Lang (именно в таком порядке).

Функция setlocale определена в стандарте ANSI С, а также соответствует стандарту POSIX.l.

Согласно ANSI С, указатель на функцию можно использовать как имя функции. При вызове функции, адрес которой содержится в этом указателе, разыменования не требуется. Например, следующими операторами определяется указатель на функцию funcptr, который содержит адрес функции foo:

extern void foo (double xyz, const int* Iptr); void (*funcptr)(double, const int*) = foo;



[ 1 ] 2 3 4 ... 98

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика