
- •Введение в системное программирование Основные понятия и определения Программы и программное обеспечение
- •Системное программирование
- •Этапы подготовки программы
- •Системное программирование
- •Лекция 1
- •1. Язык Си: Общая характеристика, историческая справкаи основные достоинства
- •2. Подготовка к выполнению и выполнение программ
- •3. Элементы языка с
- •Лекция 2
- •1. Понятие типа данных. Переменные и константы. Операция присваивания
- •2.Типы данных в языке си. Описание данных в программе
- •3. Константы в языке Си
- •4. Арифметические операции и арифметические выражения
- •5. Операции отношения, логические операции и логические выражения
- •6. Автоматическое преобразрвание типов и операция приведения
- •7. Простейшие операторы языка си. Составной оператор
- •Лекция 3
- •3. Инициализация переменных и массивов
- •4. Управляющие конструкции языка си
- •Лекция 4
- •1. Адреса и указатели
- •2. Отождествление массивов и указателей.Адресная арифметика
- •3. Указатели на массивы. Массивы указателей и многомерные массивы
- •4. Динамическое выделение памяти под массивы
- •5. Инициализация указателей
- •Лекция 5
- •1. Функции в языке си. Формальные и фактические параметры. Механизм передачи параметров. Возвращаемые значения
- •2. Использование указателей в качестве аргументов функций
- •3. Предварительное описание функций
- •4. Аргументы командной строки
- •Лекция 6
- •1. Ввод и вывод в языке си: Общие концепции
- •2. Файлы данных и каталоги. Внутренняя организация и типы файлов
- •3. Стандартные функции для работы с файлами и каталогами
- •4. Внешние устройства как специальные файлы. Организация обмена со стандартными внешними устройствами
- •5. Операции ввода/вывода через порты микропроцессоров intel 8086/80286
- •Лекция 7
- •1. Общая структура программы на языке си. Время существования и видимость переменных. Блоки
- •2. Классы памяти
- •3. Рекурсивные вызовы функций. Реализация рекурсивных алгоритмов
- •4. Препроцессор языка Си
- •5. Модели памяти, поддерживаемые компилятором ibm c/2
- •Лекция 8
- •1. Структуры в языке си: основные понятия
- •2. Массивы структур
- •3. Указатели на структуры
- •4. Вложение структур
- •5. Структуры и функции
- •6. Объединения
- •7. Перечисления
- •8. Определение и использование новых типов данных
- •9. Классы имен
3. Предварительное описание функций
Ввиду того, что отдельные функции, входящие в состав какой-либо программы на языке Си, являются абсолютно независимыми одна от другой в семантическом отношении, каждая из них может быть определена в произвольном месте исходного файла, в отдельном файле или находиться в одной из внешних библиотек. Такая организация Си-программы, обладающая большой гибкостью и полностью отвечающая требованиям структурного программирования, в определенном смысле затрудняет осуществление контроля со стороны компилятора за взаимным соответствием типов и количества формальных и фактических параметров, а также за правильностью типа возвращаемого той или иной функцией значения. Причина этого заключается в том, что любая функция может быть вызвана в работу раньше, чем она определена в текущем файле, и в такой ситуации компилятор не имеет возможности следить за правильностью вызова. Это утверждение тем более справедливо при обращении к внешним и библиотечным функциям. В подобных случаях компилятор пытается интерпретировать вызов некоторым стандартным образом, присваивая возвращаемому функцией значению тип int и не выполняя проверки правильности списка аргументов. В то же время, возможное несоответствие типов и количества формальных и фактических параметров или отличие типа реально возвращаемого функцией значения от int могут привести к трудно обнаруживаемым ошибкам в программе. Простой выход из этого положения заключается в составлении предварительного описания, или прототипа, вызываемой функции, в котором будут определены основные ее атрибуты. В самом общем случае такое предварительное описание имеет следующий формат:
<sc-specifier> <type-specifier> declarator (<arg-list>)
<, declarator(<arg-list>) ... >;
Здесь sc-specifier задает класс памяти (static или extern), который имеет вызываемая функция (см. Лекцию 7, $ 2), type-specifier устанавливает тип возвращаемого ей значения, а arg-list определяет количество и тип аргументов. Declarator в приведенной схеме является идентификатором функции, возможно модифицированным при помощи круглых скобок и символа звездочка для указателей на функции и функций, возвращающих указатели. Список аргументов arg-list обычно представляет собой последовательность разделенных запятыми имен типов данных, поддерживаемых имеющимся компилятором языка или предварительно определенных при помощи инструкции typedef (см. Лекцию 8, $ 8). Однако он также может содержать и обычные описания переменных вида float g. Использование ключевого слова void на месте arglist позволяет объвить функцию, не имеющую параметров. Поскольку функции в языке Си могут возвращать любые значения, кроме массивов и других функций, typespecifier может задавать любой простой тип данных, а также структуру, объединение или перечисление (см. Лекцию 8). В тех случаях, когда функция не вырабатывает никакого значения или возвращает указатель неопределенного типа (см. Лекцию 4, $ 1), ее предварительное описание должно начинаться с ключевого слова void, стоящего на месте имени типа возвращаемого значения. Введенное таким образом понятие предварительного описания функции дает возможность компилятору построить некоторый шаблон этой функции до ее фактического определения в текущем или внешнем файле. Этот шаблон может быть использован для контроля правильности типа возвращаемого функцией значения и соответствия формальных и фактических параметров. Ниже приведены несколько характерных примеров построения предварительных описаний.
1. В этом примере описана функция с именем add, возвращающая значение типа double и оба аргумента которой являются указателями на тип float:
double add(float*, float*);
2. Если функция с именем sum имеет два аргумента типа double и возвращает указатель на массив трех элементов типа double, то ее предварительное описание должно иметь следующий вид:
double (*sum(double, double))[3];
3. В том случае, когда функция не имеет аргументов и возврашает указатель неопределенного типа, в ее предварительном описании необходимо использовать ключевое слово void на месте имени типа возвращаемого значения и списка аргументов:
void *draw(void);