Директива связывания не может появиться внутри тела функции. Следующий фрагмент кода вызывает ошибку компиляции:
int main() {
// ошибка: директива связывания не может появиться
// внутри тела функции
extern "C" double sqrt( double );
double getValue(); //правильно
double result = sqrt ( getValue() );
//...
return 0;
}
Если мы переместим директиву так, чтобы она оказалась вне тела main(), программа откомпилируется правильно:
extern "C" double sqrt( double );
int main() {
double getValue(); //правильно
double result = sqrt ( getValue() );
//...
return 0;
}
Однако более подходящее место для директивы связывания – заголовочный файл, где находится объявление функции, описывающее ее интерфейс.
Как сделать С++ функцию доступной для программы на С? Директива extern "C" поможет и в этом:
// функция calc() может быть вызвана из программы на C
extern "C" double calc( double dparm ) { /* ... */ }
Если в одном файле имеется несколько объявлений функции, то директива связывания может быть указана при каждом из них или только при первом – в этом случае она распространяется и на все последующие объявления. Например:
// ---- myMath.h ----
extern "C" double calc( double );
// ---- myMath.C ----
// объявление calc() в myMath.h
#include "myMath.h"
// определение функции extern "C" calc()
// функция calc() может быть вызвана из программы на C
double calc( double dparm ) { // ... }
В данном разделе мы видели примеры директивы связывания extern "C" только для языка С. Это единственный внешний язык, поддержку которого гарантирует стандарт С++. Конкретная реализация может поддерживать связь и с другими языками. Например, extern "Ada" для функций, написанных на языке Ada; extern "FORTRAN" для языка FORTRAN и т.д. Мы описали один из случаев использования ключевого слова extern в С++. В разделе 8.2 мы покажем, что это слово имеет и другое назначение в объявлениях функций и объектов.
Упражнение 7.14
exit(), printf(), malloc(), strcpy() и strlen() являются функциями из библиотеки С. Модифицируйте приведенную ниже С-программу так, чтобы она компилировалась и связывалась в С++.
const char *str = "hello";
void *malloc( int );
char *strcpy( char *, const char * );
int printf( const char *, ... );
int exit( int );
int strlen( const char * );
int main()
{ /* программа на языке С */
char* s = malloc( strlen(str)+l );
strcpy( s, str );
printf( "%s, world\n", s );
exit( 0 );
}
7.8. Функция main(): разбор параметров командной строки
При запуске программы мы, как правило, передаем ей информацию в командной строке. Например, можно написать
prog -d -o of lie dataO
Фактические параметры являются аргументами функции main() и могут быть получены из массива C-строк с именем argv; мы покажем, как их использовать.
Во всех предыдущих примерах определение main() содержало пустой список:
int main() { ... }
Развернутая сигнатура main() позволяет получить доступ к параметрам, которые были заданы пользователем в командной строке:
int main( int argc, char *argv[] ){...}
argc содержит их количество, а argv – C-строки, представляющие собой отдельные значения (в командной строке они разделяются пробелами). Скажем, при запуске команды
prog -d -o ofile data0
argc получает значение 5, а argv включает следующие строки:
argv[ 0 ] = "prog";
argv[ 1 ] = "-d";
argv[ 2 ] = "-o";
argv[ 3 ] = "ofile";
argv[ 4 ] = "dataO";
В argv[0] всегда входит имя команды (программы). Элементы с индексами от 1 до argc-1 служат параметрами.
Посмотрим, как можно извлечь и использовать значения, помещенные в argv. Пусть программа из нашего примера вызывается таким образом:
prog [-d] [-h] [-v]
[-o output_file] [-l limit_value]
file_name
[ file_name [file_name [ ... ]]]
Параметры в квадратных скобках являются необязательными. Вот, например, запуск программы с их минимальным количеством – одним лишь именем файла:
prog chap1.doc
Но можно запускать и так:
prog -l 1024 -o chap1-2.out chapl.doc chap2.doc
prog d chap3.doc
prog -l 512 -d chap4.doc
При разборе параметров командной строки выполняются следующие основные шаги:
По очереди извлечь каждый параметр из argv. Мы используем для этого цикл for с начальным индексом 1 (пропуская, таким образом, имя программы):
for ( int ix = 1; ix argc; ++ix ) {
char *pchar = argv[ ix ];