Брайан Керниган - Язык программирования Си. Издание 3-е, исправленное
- Название:Язык программирования Си. Издание 3-е, исправленное
- Автор:
- Жанр:
- Издательство:Невский Диалект
- Год:2001
- Город:Санкт-Петербург
- ISBN:0-13-110362-8
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Брайан Керниган - Язык программирования Си. Издание 3-е, исправленное краткое содержание
Книга широко известных авторов, разработчиков языка Си, переработанная и дополненная с учетом стандарта ANSI для языка Си, 2-е английское издание которой вышло в 1988 году, давно стала классикой для всех изучающих и/или использующих как Си, так и Си++. Русский перевод этой книги впервые был выпущен изд- вом "Финансы и статистика" в 1992 г. и с тех пор пользуется неизменным спросом читателей.
Для настоящего третьего русского издания перевод заново сверен с оригиналом, в него внесены некоторые поправки, учитывающие устоявшиеся за прошедшие годы изменения в терминологии, а так же учтены замечания, размещенные автором на странице http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html.
Для программистов, преподавателей и студентов.
Издание подготовлено при участии издательства "Финансы и статистика"
Язык программирования Си. Издание 3-е, исправленное - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
4.5 Заголовочные файлы
Теперь представим себе, что компоненты программы-калькулятора имеют существенно большие размеры, и зададимся вопросом, как в этом случае распределить их по нескольким файлам. Программу main поместим в файл, который мы назовем main.с ; push , pop и их переменные расположим во втором файле, stack.с ; a getop - в третьем, getop.c . Наконец, getch и ungetch разместим в четвертом файле getch.с ; мы отделили их от остальных функций, поскольку в реальной программе они будут получены из заранее скомпилированной библиотеки.
Существует еще один момент, о котором следует предупредить читателя, - определения и объявления совместно используются несколькими файлами. Мы бы хотели, насколько это возможно, централизовать эти объявления и определения так, чтобы для них существовала только одна копия. Тогда программу в процессе ее развития будет легче и исправлять, и поддерживать в нужном состоянии. Для этого общую информацию расположим в заголовочном файле calc.h , который будем по мере необходимости включать в другие файлы. (Строка #include описывается в параграфе 4.11) В результате получим программу, файловая структура которой показана ниже:
main.с:
#include ‹stdio.h›
#include ‹stdlib.h›
#include "calc.h"
#define MAXOP 100
main() {
…
}
calc.h:
#define NUMBER '0'
void push(double);
double pop(void);
int getop(char[]);
int getch(void);
void ungetch(int);
getop.c:
#include ‹stdio.h›
#include ‹ctype.h›
#include "calc.h"
getop (){
…
}
getch.c:
#include ‹stdio.h›
#define BUFSIZE 100
char buf[BUFSIZE];
intbufp = 0;
int getch(void) {
…
}
void ungetch(int) {
…
}
stack.с:
#include ‹stdio.h›
#include "calc.h"
#define MAXVAL 100
int sp = 0;
double val[MAXVAL];
void push(double) {
…
}
double pop(void) {
…
}
Неизбежен компромисс между стремлением, чтобы каждый файл владел только той информацией, которая ему необходима для работы, и тем, что на практике иметь дело с большим количеством заголовочных файлов довольно трудно. Для программ, не превышающих некоторого среднего размера, вероятно, лучше всего иметь один заголовочный файл, в котором собраны вместе все объекты, каждый из которых используется в двух различных файлах; так мы здесь и поступили. Для программ больших размеров потребуется более сложная организация с большим числом заголовочных файлов.
4.6 Статические переменные
Переменные sp и val в файле stack.с , а также buf и bufp в getch.с находятся в личном пользовании функций этих файлов, и нет смысла открывать к ним доступ кому-либо еще. Указание static, примененное к внешней переменной или функции, ограничивает область видимости соответствующего объекта концом файла. Это способ скрыть имена. Так, переменные buf и bufp должны быть внешними, поскольку их совместно используют функции getch и ungetch , но их следует сделать невидимыми для "пользователей" функций getch и ungetch .
Статическая память специфицируется словом static, которое помещается перед обычным объявлением. Если рассматриваемые нами две функции и две переменные компилируются в одном файле, как в показанном ниже примере:
static char buf[BUFSIZE]; /* буфер для ungetch */
static int bufp = 0; /* след. свободная позиция в buf */
int getch(void) {…}
void ungetch(int с) {…}
то никакая другая программа не будет иметь доступ ни к buf , ни к bufp , и этими именами можно свободно пользоваться в других файлах для совсем иных целей. Точно так же, помещая указание staticперед объявлениями переменных sp и val , с которыми работают только push и pop , мы можем скрыть их от остальных функций.
Указание staticчаще всего используется для переменных, но с равным успехом его можно применять и к функциям. Обычно имена функций глобальны и видимы из любого места программы. Если же функция помечена словом static, то ее имя становится невидимым вне файла, в котором она определена.
Объявление staticможно использовать и для внутренних переменных. Как и автоматические переменные, внутренние статические переменные локальны в функциях, но в отличие от автоматических, они не возникают только на период работы функции, а существуют постоянно. Это значит, что внутренние статические переменные обеспечивают постоянное сохранение данных внутри функции.
Упражнение 4.11. Модифицируйте функцию getop так, чтобы отпала необходимость в функции ungetch . Подсказка: используйте внутреннюю статическую переменную.
4.7 Регистровые переменные
Объявление registerсообщает компилятору, что данная переменная будет интенсивно использоваться. Идея состоит в том, чтобы переменные, объявленные register, разместить на регистрах машины, благодаря чему программа, возможно, станет более короткой и быстрой. Однако компилятор имеет право проигнорировать это указание. Объявление registerвыглядит следующим образом:
register int х;
register char с;
и т. д. Объявление registerможет применяться только к автоматическим переменным и к формальным параметрам функции. Для последних это выглядит так:
f(register unsigned m, register long n)
{
register int i;
…
}
На практике существуют ограничения на регистровые переменные, что связано с возможностями аппаратуры. Располагаться в регистрах может лишь небольшое число переменных каждой функции, причем только определенных типов. Избыточные объявления registerни на что не влияют, так как игнорируются в отношении переменных, которым не хватило регистров или которые нельзя разместить на регистре. Кроме того, применительно к регистровой переменной независимо от того, выделен на самом деле для нее регистр или нет, не определено понятие адреса (см. главу 5). Конкретные ограничения на количество и типы регистровых переменных зависят от машины.
4.8 Блочная структура
Поскольку функции в Си нельзя определять внутри других функций, он не является языком, допускающим блочную структуру программы в том смысле, как это допускается в Паскале и подобных ему языках. Но переменные внутри функций можно определять в блочно-структурной манере. Объявления переменных (вместе с инициализацией) разрешено помещать не только в начале функции, но и после любой левой фигурной скобки, открывающей составную инструкцию. Переменная, описанная таким способом, "затеняет" переменные с тем же именем, расположенные в объемлющих блоках, и существует вплоть до соответствующей правой фигурной скобки. Например, в
Читать дальшеИнтервал:
Закладка: