Главная » Просмотр файлов » Бьерн Страуструп

Бьерн Страуструп (947334), страница 22

Файл №947334 Бьерн Страуструп (Стpаустpуп - Книга о C++) 22 страницаБьерн Страуструп (947334) страница 222013-09-15СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 22)

class V { /* ... */ }

Описания функций extern int strlen(const char*);

Определения inline char get() { return *p++; }

функций-подстановок

Описания данных extern int a;

Определения констант const float pi = 3.141593;

Перечисления enum bool { false, true };

Описания имен class Matrix;

Команды включения файлов #include <signal.h>

Макроопределения #define Case break;case

Комментарии /* проверка на конец файла */

Перечисление того, что стоит помещать в заголовочный файл, не является

требованием языка, это просто совет по разумному использованию включения

файлов. С другой стороны, в заголовочном файле никогда не должно быть:

Определений обычных функций char get() { return *p++; }

Определений данных int a;

Определений составных const tb[i] = { /* ... */ };

констант

По традиции заголовочные файлы имеют расширение .h, а файлы,

содержащие определения функций или данных, расширение .c. Иногда

их называют "h-файлы" или "с-файлы" соответственно. Используют

и другие расширения для этих файлов: .C, cxx, .cpp и

.cc. Принятое расширение вы найдете в своем справочном руководстве.

Макросредства описываются в $$4.7. Отметим только, что в С++ они

используются не столь широко, как в С, поскольку С++ имеет определенные

возможности в самом языке: определения констант (const),

функций-подстановок (inline), дающие возможность более простой

операции вызова, и шаблонов типа, позволяющие порождать семейство

типов и функций ($$8).

Совет помещать в заголовочный файл определения только простых,

но не составных, констант объясняется вполне прагматической причиной.

Просто большинство трансляторов не настолько разумно, чтобы

предотвратить создание ненужных копий составной константы. Вообще

говоря, более простой вариант всегда является более общим, а значит

транслятор должен учитывать его в первую очередь, чтобы создать

хорошую программу.

4.3.1 Единственный заголовочный файл

Проще всего разбить программу на несколько файлов следующим

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

число входных файлов, а все типы, необходимые для связи между

ними, описать в единственном заголовочном файле. Все входные

файлы будут включать заголовочный файл. Программу

калькулятора можно разбить на четыре входных файла .c:

lex.c, syn.c, table.c и main.c. Заголовочный файл dc.h будет

содержать описания каждого имени, которое используется более

чем в одном .c файле:

// dc.h: общее описание для калькулятора

#include <iostream.h>

enum token_value {

NAME, NUMBER, END,

PLUS='+', MINUS='-', MUL='*', DIV='/',

PRINT=';', ASSIGN='=', LP='(', RP=')'

};

extern int no_of_errors;

extern double error(const char* s);

extern token_value get_token();

extern token_value curr_tok;

extern double number_value;

extern char name_string[256];

extern double expr();

extern double term();

extern double prim();

struct name {

char* string;

name* next;

double value;

};

extern name* look(const char* p, int ins = 0);

inline name* insert(const char* s) { return look(s,1); }

Если не приводить сами операторы, lex.c должен иметь такой вид:

// lex.c: ввод и лексический анализ

#include "dc.h"

#include <ctype.h>

token_value curr_tok;

double number_value;

char name_string[256];

token_value get_token() { /* ... */ }

Используя составленный заголовочный файл, мы добьемся,

что описание каждого объекта, введенного пользователем, обязательно

окажется в том файле, где этот объект определяется. Действительно,

при обработке файла lex.c транслятор столкнется с описаниями

extern token_value get_token();

// ...

token_value get_token() { /* ... */ }

Это позволит транслятору обнаружить любое расхождение в типах,

указанных при описании данного имени. Например, если бы функция

get_token() была описана с типом token_value, но определена с

типом int, трансляция файла lex.c выявила бы ошибку: несоответствие

типа.

Файл syn.c может иметь такой вид:

// syn.c: синтаксический анализ и вычисления

#include "dc.h"

double prim() { /* ... */ }

double term() { /* ... */ }

double expr() { /* ... */ }

Файл table.c может иметь такой вид:

// table.c: таблица имен и функция поиска

#include "dc.h"

extern char* strcmp(const char*, const char*);

extern char* strcpy(char*, const char*);

extern int strlen(const char*);

const int TBLSZ = 23;

name* table[TBLSZ];

name* look(char* p, int ins) { /* ... */ }

Отметим, что раз строковые функции описаны в самом файле table.c,

транслятор не может проверить согласованность этих описаний по типам.

Всегда лучше включить соответствующий заголовочный файл,

чем описывать в файле .c некоторое имя как extern. Это может

привести к включению "слишком многого", но такое включение нестрашно,

поскольку не влияет на скорость выполнения программы и ее размер, а

программисту позволяет сэкономить время. Допустим, функция strlen() снова

описывается в приведенном ниже файле main.c. Это только лишний

ввод символов и потенциальный источник ошибок, т.к. транслятор

не сможет обнаружить расхождения в двух описаниях strlen() (впрочем,

это может сделать редактор связей). Такой проблемы не возникло бы,

если бы в файле dc.h содержались все описания extern, как первоначально

и предполагалось. Подобная небрежность присутствует в нашем примере,

поскольку она типична для программ на С. Она очень естественна

для программиста, но часто приводит к ошибкам и таким программам,

которые трудно сопровождать. Итак, предупреждение сделано!

Наконец, приведем файл main.c:

// main.c: инициализация, основной цикл, обработка ошибок

#include "dc.h"

double error(char* s) { /* ... */ }

extern int strlen(const char*);

int main(int argc, char* argv[]) { /* ... */ }

В одном важном случае заголовочные файлы вызывают большое неудобство.

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

библиотеки расширяют возможности языка, вводя множество типов (как

общих, так и рассчитанных на конкретные приложения; см. главы 5-9).

В таком случае текст каждой единицы трансляции может начинаться

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

файлов библиотеки, как правило, стабильно и меняется редко. Здесь

очень пригодился бы претранслятор, который обрабатывает его. По сути,

нужен язык специального назначения со своим транслятором. Но устоявшихся

методов построения такого претранслятора пока нет.

4.3.2 Множественные заголовочные файлы

Разбиение программы в расчете на один заголовочный файл больше

подходит для небольших программ, отдельные части которых не

имеют самостоятельного назначения. Для таких программ допустимо,

что по заголовочному файлу нельзя определить, чьи описания там

находятся и по какой причине. Здесь могут помочь только комментарии.

Возможно альтернативное решение: пусть каждая часть программы

имеет свой заголовочный файл, в котором определяются средства,

предоставляемые другим частям. Теперь для каждого файла .c будет

свой файл .h, определяющий, что может предоставить первый. Каждый файл

.c будет включать как свой файл .h, так и некоторые другие файлы .h,

исходя из своих потребностей.

Попробуем использовать такую организацию программы для

калькулятора. Заметим, что функция error() нужна практически во всех

функциях программы, а сама использует только <iostream.h>. Такая

ситуация типична для функций, обрабатывающих ошибки.

Следует отделить ее от файла main.c:

// error.h: обработка ошибок

extern int no_of_errors;

extern double error(const char* s);

// error.c

#include <iostream.h>

#include "error.h"

int no_of_errors;

double error(const char* s) { /* ... */ }

При таком подходе к разбиению программы каждую пару файлов .c

и .h можно рассматривать как модуль, в котором файл .h задает

его интерфейс, а файл .c определяет его реализацию.

Таблица имен не зависит ни от каких частей калькулятора, кроме

части обработки ошибок. Теперь этот факт можно выразить

явно:

// table.h: описание таблицы имен

struct name {

char* string;

name* next;

double value;

};

extern name* look(const char* p, int ins = 0);

inline name* insert(const char* s) { return look(s,1); }

// table.h: определение таблицы имен

#include "error.h"

#include <string.h>

#include "table.h"

const int TBLSZ = 23;

name* table[TBLSZ];

name* look(const char* p, int ins) { /* ... */ }

Заметьте, что теперь описания строковых функций берутся из включаемого

файла <string.h>. Тем самым удален еще один источник ошибок.

// lex.h: описания для ввода и лексического анализа

enum token_value {

NAME, NUMBER, END,

PLUS='+', MINUS='-', MUL='*',

PRINT=';', ASSIGN='=', LP='(', RP= ')'

};

extern token_value curr_tok;

extern double number_value;

extern char name_string[256];

extern token_value get_token();

Интерфейс с лексическим анализатором достаточно запутанный. Поскольку

недостаточно соответствующих типов для лексем, пользователю

функции get_token() предоставляются те же буферы number_value

и name_string, с которыми работает сам лексический анализатор.

// lex.c: определения для ввода и лексического анализа

#include <iostream.h>

#include <ctype.h>

#include "error.h"

#include "lex.h"

token_value curr_tok;

double number_value;

char name_string[256];

token_value get_token() { /* ... */ }

Интерфейс с синтаксическим анализатором определен четко:

// syn.h: описания для синтаксического анализа и вычислений

extern double expr();

extern double term();

extern double prim();

// syn.c: определения для синтаксического анализа и вычислений

#include "error.h"

#include "lex.h"

#include "syn.h"

double prim() { /* ... */ }

double term() { /* ... */ }

double expr() { /* ... */ }

Как обычно, определение основной программы тривиально:

// main.c: основная программа

#include <iostream.h>

#include "error.h"

#include "lex.h"

#include "syn.h"

#include "table.h"

int main(int argc, char* argv[]) { /* ... */ }

Какое число заголовочных файлов следует использовать для данной

программы зависит от многих факторов. Большинство их определяется

способом обработки файлов именно в вашей системе, а не

собственно в С++. Например, если ваш редактор не может работать

одновременно с несколькими файлами, диалоговая обработка нескольких

заголовочных файлов затрудняется. Другой пример: может оказаться,

что открытие и чтение 10 файлов по 50 строк каждый занимает

существенно больше времени, чем открытие и чтение одного файла из 500

строк. В результате придется хорошенько подумать, прежде чем

разбивать небольшую программу, используя множественные заголовочные

файлы. Предостережение: обычно можно управиться с множеством, состоящим

примерно из 10 заголовочных файлов (плюс стандартные заголовочные

файлы). Если же вы будете разбивать программу на минимальные логические

единицы с заголовочными файлами (например, создавая для каждой структуры

свой заголовочный файл), то можете очень легко получить неуправляемое

множество из сотен заголовочных файлов.

4.4 Связывание с программами на других языках

Программы на С++ часто содержат части, написанные на других языках, и

наоборот, часто фрагмент на С++ используется в программах,

написанных на других языках. Собрать в одну программу

фрагменты, написанные на разных языках, или, написанные на одном

языке, но в системах программирования с разными соглашениями о

связывании, достаточно трудно. Например, разные языки или разные

реализации одного языка могут различаться использованием регистров

при передаче параметров, порядком размещения параметров в стеке,

упаковкой таких встроенных типов, как целые или строки, форматом

Характеристики

Тип файла
Документ
Размер
4,26 Mb
Тип материала
Учебное заведение
Неизвестно

Список файлов книги

Свежие статьи
Популярно сейчас
Как Вы думаете, сколько людей до Вас делали точно такое же задание? 99% студентов выполняют точно такие же задания, как и их предшественники год назад. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6418
Авторов
на СтудИзбе
307
Средний доход
с одного платного файла
Обучение Подробнее