Директива связывания extern "C" A
Если программист хочет использовать функцию, написанную на другом языке, в частности на С, то компилятору нужно указать, что при вызове требуются несколько иные условия. Скажем, имя функции или порядок передачи аргументов различаются в зависимости от языка программирования.
Показать, что функция написана на другом языке, можно с помощью директивы связывания в форме простой либо составной инструкции:
// директива связывания в форме простой инструкции extern "C" void exit(int); // директива связывания в форме составной инструкции extern "C" { int printf( const char* ... ); int scanf( const char* ... ); } // директива связывания в форме составной инструкции extern "C" { #include <cmath> |
}
Первая форма такой директивы состоит из ключевого слова extern, за которым следует строковый литерал, а за ним – “обычное” объявление функции. Хотя функция написана на другом языке, проверка типов вызова выполняется полностью. Несколько объявлений функций могут быть помещены в фигурные скобки составной инструкции директивы связывания – второй формы этой директивы. Скобки отмечают те объявления, к которым она относится, не ограничивая их видимости, как в случае обычной составной инструкции. Составная инструкция extern "C" в предыдущем примере говорит только о том, что функции printf() и scanf()
написаны на языке С. Во всех остальных отношениях эти объявления работают точно так же, как если бы они были расположены вне инструкции.
Если в фигурные скобки составной директивы связывания помещается директива препроцессора #include, все объявленные во включаемом заголовочном файле функции рассматриваются как написанные на языке, указанном в этой директиве. В предыдущем примере все функции из заголовочного файла cmath написаны на языке С.
Директива связывания не может появиться внутри тела функции. Следующий фрагмент кода вызывает ошибку компиляции:
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 |
Если в одном файле имеется несколько объявлений функции, то директива связывания может быть указана при каждом из них или только при первом – в этом случае она распространяется и на все последующие объявления. Например:
// ---- myMath.h ---- extern "C" double calc( double ); // ---- myMath.C ---- // объявление calc() в myMath.h #include "myMath.h" // определение функции extern "C" calc() // функция calc() может быть вызвана из программы на C |
В данном разделе мы видели примеры директивы связывания 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 ); |