Бьерн Страуструп. Язык программирования С++



бет32/124
Дата16.07.2016
өлшемі3.27 Mb.
#204081
түріКнига
1   ...   28   29   30   31   32   33   34   35   ...   124

4.5 Как создать библиотеку


Распространены такие обороты (и в этой книге тоже): "поместить

в библиотеку", "поискать в такой-то библиотеке". Что они

означают для программ на С++? К сожалению, ответ зависит от

используемой системы. В этом разделе говорится о том, как

создать и использовать библиотеку для десятой версии системы ЮНИКС.

Другие системы должны предоставлять похожие возможности. Библиотека

состоит из файлов .o, которые получаются в результате трансляции

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

содержатся необходимые для вызова файлов .o описания.

Рассмотрим в качестве примера, как для четко не оговоренного множества

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

множество стандартных математических функций. Заголовочный файл

может иметь такой вид:


extern "C" { // стандартные математические функции

// как правило написаны на С


double sqrt(double); // подмножество

double sin(double);

double cos(double);

double exp(double);

double log(double);

// ...
}


Определения этих функций будут находиться в файлах sqrt.c, sin.c,

cos.c, exp.c и log.c, соответственно.

Библиотеку с именем math.a можно создать с помощью таких

команд:
$ CC -c sqrt.c sin.c cos.c exp.c log.c

$ ar cr math.a sqrt.o sin.o cos.o exp.o log.o

$ ranlib math.a


Здесь символ $ является приглашением системы.

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

с теми же именами. Команда ar (архиватор) создает архив под именем

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

Если в вашей системе нет команды ranlib (возможно она и не нужна),

то, по крайней мере, можно найти в справочном руководстве

ссылку на имя ar. Чтобы использовать библиотеку в своей

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


$ CC myprog.c math.a
Встает вопрос: что дает нам библиотека math.a? Ведь можно было бы

непосредственно использовать файлы .o, например так:


$ CC myprog.c sqrt.o sin.o cos.o exp.o log.o
Дело в том, что во многих случаях трудно правильно указать, какие

файлы .o действительно нужны. В приведенной выше команде

использовались все из них. Если же в myprog вызываются только

sqrt() и cos(), тогда, видимо, достаточно задать такую команду:


$ CC myprog.c sqrt.o cos.o
Но это будет неверно, т.к. функция cos() вызывает sin().

Редактор связей, который вызывается командой CC для обработки

файлов .a (в нашем случае для файла math.a), умеет из множества

файлов, образующих библиотеку, извлекать только нужные файлы

.o. Иными словами, связывание с библиотекой позволяет включать

в программы много определений одного имени (в том числе определения

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

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

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

число определений.




4.6 Функции


Самый распространенный способ задания в С++ каких-то действий - это

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

есть описание того, как их выполнить. Неописанные функции

вызывать нельзя.

4.6.1 Описания функций


Описание функции содержит ее имя, тип возвращаемого значения

(если оно есть) и число и типы параметров, которые должны

задаваться при вызове функции. Например:


extern double sqrt(double);

extern elem* next_elem();

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

extern void exit(int);


Семантика передачи параметров тождественна семантике

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

нужно, происходят неявные преобразования типов. Так, если

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


double sr2 = sqrt(2);
содержится правильный вызов функции sqrt() со значением с плавающей

точкой 2.0. Контроль и преобразование типа фактического параметра

имеет в С++ огромное значение.

В описании функции можно указывать имена параметров. Это

облегчает чтение программы, но транслятор эти имена просто

игнорирует.



4.6.2 Определения функций


Каждая вызываемая в программе функция должна быть где-то в ней

определена, причем только один раз. Определение функции - это ее

описание, в котором содержится тело функции. Например:


extern void swap(int*, int*); // описание
void swap(int* p, int* q) // определение

{

int t = *p;



*p = *q;

*q = *t;


}
Не так редки случаи, когда в определении функции не используются

некоторые параметры:


void search(table* t, const char* key, const char*)

{

// третий параметр не используется


// ...

}
Как видно из этого примера, параметр не используется, если

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

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

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

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

содержащие вызов данной, не придется менять.

Уже говорилось, что функцию можно определить как подстановку

(inline). Например:
inline fac(int i) { return i<2 ? 1 : n*fac(n-1); }
Спецификация inline служит подсказкой транслятору, что вызов

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

обычного механизма вызова функций ($$R.7.1.2). Хороший оптимизирующий

транслятор вместо генерации вызова fac(6) может просто использовать

константу 720. Из-за наличия взаиморекурсивных вызовов функций-подстановок,

а также функций-подстановок, рекурсивность которых зависит от входных

данных, нельзя утверждать, что каждый вызов функции-подстановки

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

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

трансляторы создадут команды 6*5*4*3*2*1, другие - 6*fac(5), а

некоторые ограничатся неоптимизированным вызовом fac(6).

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

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

только определение, но и описание функции-подстановки находилось

в текущей области видимости. В остальном спецификация inline

не влияет на семантику вызова.





Достарыңызбен бөлісу:
1   ...   28   29   30   31   32   33   34   35   ...   124




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет