Чтение онлайн

ЖАНРЫ

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

double square(double d)

{

return d*d;

}

void ff

{

double x = square(2); /* OK: переводим 2 в 2.0 и вызываем */

double y = square; /* пропущен аргумент */

double y = square("Hello"); /* ошибка: неправильный тип

аргументов */

double y = square(2,3); /* ошибка: слишком много аргументов */

}

Определение

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

void f { /* что-то делает */ }

void g

{

f(2); /* OK в языке C; ошибка в языке C++ */

}

Код

void f; /* не указан тип аргумента */

означающий, что функция

f
может принять любое количество аргументов любого типа, выглядит действительно странно. В ответ на это я изобрел новое обозначение, в котором понятие “ничего” указывалось явным образом с помощью ключевого слова
void
(void — слово из четырех букв, означающее “ничего”).

void f(void); /* не принимает никаких аргументов */

Впрочем, вскоре я об этом пожалел, потому что эта конструкция выглядит странно и при последовательной проверке типов аргументов является излишней. Что еще хуже, Деннис Ритчи (автор языка C) и Дуг Мак-Илрой (Doug McIlroy) (законодатель мод в Исследовательском центре компьютерных наук в компании Bell Labs (Bell Labs Computer Science Research Center; см. раздел 22.2.5) назвали это решение “отвратительным”. К сожалению, оно стало очень популярным среди программистов, работающих на языке С. Тем не менее не используйте его в программах на языке С++, в которых оно выглядит не только уродливо, но и является совершенно излишним.

В языке C есть альтернативное определение функции в стиле языка Algol-60, в котором типы параметров (не обязательно) указываются отдельно от их имен.

int old_style(p,b,x) char* p; char b;

{

/* ... */

}

Это определение “в старом стиле” предвосхищает конструкции языка С++ и не является прототипом. По умолчанию аргумент без объявленного типа считается аргументов типа
int
. Итак, параметр
x
является аргументом функции
old_style
, имеющим тип
int
. Мы можем вызвать функцию
old_style
следующим образом:

old_style; /* OK: пропущены все аргументы */

old_style("hello",'a',17); /* OK: все аргументы имеют правильный тип */

old_style(12,13,14); /* OK: 12 — неправильный тип */

/* но old_style может не использовать p */

Компилятор должен пропустить эти вызовы (но мы надеемся, что он предупредит о первом и третьем аргументах).

Мы рекомендуем придерживаться следующих правил проверки типов аргументов функций.

• Последовательно используйте прототипы функций (используйте заголовочные файлы).

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

• Используйте (какую-нибудь) программу

lint
.

В

результате вы получите код, который одновременно будет кодом на языке C++.

27.2.4. Вызов функций, написанных на языке С, из программы на языке С++, и наоборот

Вы можете установить связи между файлами, скомпилированными с помощью компилятора языка С, и файлами, скомпилированными с помощью компилятора языка С++, только если компиляторы предусматривают такую возможность. Например, можете связать объектные файлы, сгенерированные из кода на языке С и С++, используя компиляторы GNU C и GCC. Можете также связать объектные файлы, сгенерированные из кода на языке С и С++, используя компиляторы Microsoft C и C++ (MSC++). Это обычная и полезная практика, позволяющая использовать больше библиотек, чем это возможно при использовании только одного из этих языков.

В языке C++ предусмотрена более строгая проверка типов, чем в языке C. В частности, компилятор и редактор связей для языка C++ проверяют, согласованно ли определены и используются функции
f(int)
и
f(double)
, даже если они определены в разных исходных файлах. Редактор связей для языка C не проводит такой проверки. Для того чтобы вызвать функцию, определенную в языке C, в программе, написанной на языке C++, и наоборот, необходимо сообщить компилятору о том, что вы собираетесь сделать.

// вызов функции на языке C из кода на языке C++:

extern "C" double sqrt(double); // связь с функцией языка C

void my_c_plus_plus_fct

{

double sr = sqrt(2);

}

По существу, выражение

extern "C"
сообщает компилятору о том, что вы используете соглашения, принятые компилятором языка С. Помимо этого, с точки зрения языка С++ в этой программе все нормально. Фактически стандартная функция
sqrt(double)
из языка C++ обычно входит и в стандартную библиотеку языка С. Для того чтобы вызвать функцию из библиотеки языка С в программе, написанной на языке С++, больше ничего не требуется. Язык C++ просто адаптирован к соглашениям, принятым в редакторе связей языка C.

Мы можем также использовать выражение

extern "C"
, чтобы вызвать функцию языка С++ из программы, написанной на языке С.

// вызов функции на языке C++ из кода на языке C:

extern "C" int call_f(S* p, int i)

{

return p–>f(i);

}

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

f
.

/* вызов функции на языке C++ из функции на языке C: */

int call_f(S* p, int i);

struct S* make_S(int,const char*);

void my_c_fct(int i)

{

/* ... */

struct S* p = make_S(x, "foo");

int x = call_f(p,i);

/* ... */

}

Для того чтобы эта конструкция работала, больше о языке С++ упоминать не обязательно.

Выгоды такого взаимодействия очевидны: код можно писать на смеси языков C и C++. В частности, программы на языке C++ могут использовать библиотеки, написанные на языке C, а программы на языке C могут использовать библиотеки, написанные на языке С++. Более того, большинство языков (особенно Fortran) имеют интерфейс вызова функций, написанных на языке С, и допускают вызов своих функций в программах, написанных на языке С.

Поделиться с друзьями: