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

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

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

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

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

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

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

связывания. Например, следующее описание объявляет strcpy внешней

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

связывания в С:

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

Результат этого описания отличается от результата обычного описания

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

только порядком связывания для вызывающих strcpy() функций. Сама

семантика вызова и, в частности, контроль фактических параметров

будут одинаковы в обоих случаях. Описание extern "C" имеет смысл

использовать еще и потому, что языки С и С++, как и их

реализации, близки друг другу. Отметим, что в описании extern "C"

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

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

Эти языки в определенной степени подчиняются порядку связывания

для С.

Утомительно добавлять "C" ко многим описаниям внешних, и

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

описаний. Например:

extern "C" {

char* strcpy(char*, const char);

int strcmp(const char*, const char*)

int strlen(const char*)

// ...

}

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

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

extern "C" {

#include <string.h>

}

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

для С получают такой файл для С++. Возможно иное решение с

помощью условной трансляции:

#ifdef __cplusplus

extern "C" {

#endif

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

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

int strlen(const char*);

// ...

#ifdef __cplusplus

}

#endif

Предопределенное макроопределение __cplusplus нужно, чтобы обойти

конструкцию extern "C" { ...}, если заголовочный файл используется

для С.

Поскольку конструкция extern "C" { ... } влияет только на

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

например:

extern "C" {

// произвольные описания

// например:

static int st;

int glob;

}

Никак не меняется класс памяти и область видимости

описываемых объектов, поэтому по-прежнему st подчиняется внутреннему

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

Укажем еще раз, что описание extern "C" влияет только на

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

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

контроля типов и преобразования фактических параметров, которые в C++

строже, чем в С. Например:

extern "C" int f();

int g()

{

return f(1); // ошибка: параметров быть не должно

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

double sqrt(double); // подмножество <math.h>

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

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

4.6.3 Передача параметров

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

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

соответствующего фактического параметра. Семантика передачи

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

типы формального и соответствующего ему фактического параметра, и

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

Существуют специальные правила передачи массивов ($$4.6.5).

Есть возможность передать параметр, минуя контроль типа ($$4.6.8),

и возможность задать стандартное значение параметра ($$4.6.7).

Рассмотрим функцию:

void f(int val, int& ref)

{

val++;

ref++;

}

При вызове f() в выражении val++ увеличивается локальная копия

первого фактического параметра, тогда как в ref++ - сам второй

фактический параметр увеличивается сам. Поэтому в функции

void g()

{

int i = 1;

int j = 1;

f(i,j);

}

увеличится значение j, но не i. Первый параметр i передается по

значению, а второй параметр j передается по ссылке. В $$2.3.10

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

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

(см. также $$10.2.2). Но большие объекты, очевидно, гораздо

эффективнее передавать по ссылке, чем по значению. Правда можно

описать параметр со спецификацией const, чтобы гарантировать, что

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

вызываемая функция не может изменить значение объекта:

void f(const large& arg)

{

// значение "arg" нельзя изменить без явных

// операций преобразования типа

}

Если в описании параметра ссылки const не указано, то это

рассматривается как намерение изменять передаваемый объект:

void g(large& arg); // считается, что в g() arg будет меняться

Отсюда мораль: используйте const всюду, где возможно.

Точно так же, описание параметра, являющегося указателем, со

спецификацией const говорит о том, что указуемый объект не будет

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

extern int strlen(const char*); // из <string.h>

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

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

Значение такого приема растет вместе с ростом программы.

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

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

const или ссылкой, а также для параметров с типом, определенным

пользователем ($1.4.2).

Литерал, константу и параметр, требующий преобразования,

можно передавать как параметр типа const&, но без спецификации

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

const T&, мы гарантируем, что он может принимать значения из того же

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

при необходимости с помощью временной переменной.

float fsqrt(const float&); // функция sqrt в стиле Фортрана

void g(double d)

{

float r;

r = fsqrt(2.0f); // передача ссылки на временную

// переменную, содержащую 2.0f

r = fsqrt(r); // передача ссылки на r

r = fsqrt(d); // передача ссылки на временную

// переменную, содержащую float(d)

}

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

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

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

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