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

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

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

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

символу из буфера.

13. (*2) Введите в программу калькулятора из $$3.1 такие функции, как

sqrt(), log() и sin(). Подсказка: задайте предопределенные

имена и вызывайте функции с помощью массива указателей на них.

Не забывайте проверять параметры, передаваемые этим

функциям.

14. (*3) Введите в калькулятор возможность определять пользовательские

функции. Подсказка: определите функцию как последовательность

операторов, будто бы заданную самим пользователем. Эту

последовательность можно хранить или как строку символов, или

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

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

иметь параметры, то придется придумать форму записи и для них.

15. (*1.5) Переделайте программу калькулятора, используя структуру

symbol вместо статических переменных name_string и number_value:

struct symbol {

token_value tok;

union {

double number_value;

char* name_string;

};

};

16.(*2.5) Напишите программу, которая удаляет все комментарии из

программы на С++. Это значит, надо читать символы из cin и

удалять комментарии двух видов: // и /* */. Получившийся текст

запишите в cout. Не заботьтесь о красивом виде получившегося

текста (это уже другая, более сложная задача). Корректность

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

//, /* и */ в комментариях, строках и символьных константах.

17. (*2) Исследуйте различные программы и выясните, какие способы

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

* ГЛАВА 4

Итерация присуща человеку,

а рекурсия - богу.

- Л. Дойч

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

транслируемых единиц, по традиции называемых файлами. В этой главе

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

каким образом они могут иметь общие данные, и как добиться

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

Подробно обсуждаются функции, в том числе:

передача параметров, перегрузка имени функции,

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

описания и определения функций. В конце главы обсуждаются

макровозможности языка.

4.1 Введение

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

область видимости ($$R.3.2). Это область видимости глобальных

функций (как статических, так и подстановок), а также глобальных

переменных (как статических, так и со спецификацией const). Кроме

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

также единицей трансляции. Обычно системы хранят, транслируют и

представляют пользователю программу на С++ как множество файлов,

хотя существуют системы, устроенные иначе. В этой главе будет

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

Всю программу поместить в один файл, как правило, невозможно,

поскольку программы стандартных функций и программы операционной

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

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

неудобно и непрактично. Разбиения программы на файлы может

облегчить понимание общей структуры программы и дает транслятору

возможность поддерживать эту структуру. Если единицей трансляции

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

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

размера время на перетрансляцию можно значительно сократить, если

ее разбить на файлы подходящего размера.

Вернемся к примеру с калькулятором. Решение было дано в виде

одного файла. Когда вы попытаетесь его транслировать, неизбежно

возникнут некоторые проблемы с порядком описаний. По крайней мере

одно "ненастоящее" описание придется добавить к тексту, чтобы

транслятор мог разобраться в использующих друг друга функциях

expr(), term() и prim(). По тексту программы видно, что она

состоит из четырех частей: лексический анализатор (сканер),

собственно анализатор, таблица имен и драйвер. Однако, этот факт

никак не отражен в самой программе. На самом деле калькулятор

не был запрограммирован именно так. Так не следует писать

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

программированию, сопровождению и оптимизации для такой "зряшной"

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

хотя бы для удобства.

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

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

достаточно сведений о типах для трансляции файла, составляющего

только часть программы. Требование непротиворечивости использования

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

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

состоящей из одного файла. Это возможно только в том случае, когда

описания, находящиеся в разных единицах трансляции, будут

согласованы. В вашей системе программирования имеются средства,

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

противоречия обнаруживает редактор связей. Редактор связей - это программа,

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

Иногда его по ошибке называют загрузчиком.

4.2 Связывание

Если явно не определено иначе, то имя, не являющееся локальным для

некоторой функции или класса, должно обозначать один и тот же тип,

значение, функцию или объект во всех единицах трансляции данной

программы. Иными словами, в программе может быть только один

нелокальный тип, значение, функция или объект с данным именем.

Рассмотрим для примера два файла:

// file1.c

int a = 1;

int f() { /* какие-то операторы */ }

// file2.c

extern int a;

int f();

void g() { a = f(); }

В функции g() используются те самые a и f(), которые определены в

файле file1.c. Служебное слово extern показывает, что описание

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

Если бы присутствовала инициализация a, то extern просто

проигнорировалось бы, поскольку описание с инициализацией всегда

считается определением. Любой объект в программе может определяться

только один раз. Описываться же он может неоднократно, но все

описания должны быть согласованы по типу. Например:

// file1.c:

int a = 1;

int b = 1;

extern int c;

// file2.c:

int a;

extern double b;

extern int c;

Здесь содержится три ошибки: переменная a определена дважды ("int a;"

- это определение, означающее "int a=0;"); b описано дважды, причем

с разными типами; c описано дважды, но неопределено. Такие ошибки

(ошибки связывания) транслятор, который обрабатывает файлы

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

обнаруживается редактором связей.

Следующая программа допустима в С, но не в С++:

// file1.c:

int a;

int f() { return a; }

// file2.c:

int a;

int g() { return f(); }

Во-первых, ошибкой является вызов f() в file2.c, поскольку в этом

файле f() не описана. Во-вторых, файлы программы не могут быть

правильно связаны, поскольку a определено дважды.

Если имя описано как static, оно становится локальном в этом

файле. Например:

// file1.c:

static int a = 6;

static int f() { /* ... */ }

// file2.c:

static int a = 7;

static int f() { /* ... */ }

Приведенная программа правильна, поскольку a и f определены как

статические. В каждом файле своя переменная a и функция f().

Если переменные и функции в данной части программы описаны как

static, то в этой части программы проще разобраться, поскольку не нужно

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

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

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

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

что объект подлежит внутреннему связыванию. Обратно, если имя

объекта или функции нелокально в данном файле, то он подлежит

внешнему связыванию.

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

не подлежат связыванию. Имена глобальных классов и перечислений

должны быть уникальными во всей программе и иметь единственное

определение. Поэтому, если есть два даже идентичных определения

одного класса, это - все равно ошибка:

// file1.c:

struct S { int a; char b; };

extern void f(S*);

// file2.c:

struct S { int a; char b; };

void f(S* p) { /* ... */ }

Но будьте осторожны: опознать идентичность двух описаний класса

не в состоянии большинство систем программирования С++. Такое

дублирование может вызвать довольно тонкие ошибки (ведь классы

в разных файлах будут считаться различными).

Глобальные функции-подстановки подлежат внутреннему связыванию,

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

т.е. имена typedef, локальны в своем файле, поэтому описания

в двух данных ниже файлах не противоречат друг другу:

// file1.c:

typedef int T;

const int a = 7;

inline T f(int i) { return i+a; }

// file2.c:

typedef void T;

const int a = 8;

inline T f(double d) { cout<<d; }

Константа может получить внешнее связывание только с помощью явного

описания:

// file3.c:

extern const int a;

const int a = 77;

// file4.c:

extern const int a;

void g() { cout<<a; }

В этом примере g() напечатает 77.

4.3 Заголовочные файлы

Типы одного объекта или функции должны быть согласованы во всех их

описаниях. Должен быть согласован по типам и входной текст,

обрабатываемый транслятором, и связываемые части программы. Есть

простой, хотя и несовершенный, способ добиться согласованности

описаний в различных файлах. Это: включить во входные файлы,

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

которые содержат интерфейсную информацию.

Средством включения текстов служит макрокоманда #include,

которая позволяет собрать в один файл (единицу трансляции)

несколько исходных файлов программы. Команда

#include "включаемый-файл"

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

включаемый-файл. Естественно, это содержимое должно быть текстом

на С++, поскольку его будет читать транслятор. Как правило, операция

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

С++. Она вызывается системой программирования перед собственно

трансляцией для обработки таких команд во входном тексте. Возможно

и другое решение: часть транслятора, непосредственно работающая

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

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

работает автор, чтобы увидеть результат команд включения файлов,

нужно задать команду:

CC -E file.c

Эта команда для обработки файла file.c запускает препроцессор

(и только!), подобно тому, как команда CC без флага -E запускает сам

транслятор.

Для включения файлов из стандартных каталогов (обычно каталоги

с именем INCLUDE) надо вместо кавычек использовать угловые скобки

< и >. Например:

#include <stream.h> // включение из стандартного каталога

#include "myheader.h" // включение из текущего каталога

Включение из стандартных каталогов имеет то преимущество, что имена

этих каталогов никак не связаны с конкретной программой (обычно

вначале включаемые файлы ищутся в каталоге /usr/include/CC, а

затем в /usr/include). К сожалению, в этой команде пробелы существенны:

#include < stream.h> // <stream.h> не будет найден

Было бы нелепо, если бы каждый раз перед включением файла

требовалась его перетрансляция. Обычно включаемые файлы содержат

только описания, а не операторы и определения, требующие существенной

трансляторной обработки. Кроме того, система программирования

может предварительно оттранслировать заголовочные

файлы, если, конечно, она настолько развита, что способна сделать

это, не изменяя семантики программы.

Укажем, что может содержать заголовочный файл:

Определения типов struct point { int x, y; };

Шаблоны типов template<class T>

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

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

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

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