Я думаю, когда функция, объявленная вперед, определяется на другом языке, чем вызов, требуется внешний интерфейс.
Я должен предупредить вас, что ваш вопрос плохо сформулирован. Я уверен, что вы заинтересованы в том, когда использовать
extern "C" int foo(int);
в C++, но я не уверен, и у меня есть надежда, что я не тратить свое время.
Давайте различать компилятор и компоновщик. Я оставляю некоторые детали, но ничего не влияет на ответ на ваш вопрос.
A Прочая декларация используется компилятором. При объявлении функции вы даете компилятору информацию о том, как он используется. Вы объявляете функцию F, а когда используется компилятор, F используется, он знает, что делать. (В K & R дней, в отсутствие объявления, компилятор использовал значения по умолчанию, иногда приводящие к веселым результатам. Поэтому теперь они являются обязательными как для C, так и для C++.)
Обычно переднее объявление функции представляет собой функциональный прототип : он предоставляет типы параметров. В C это не является строго необходимым. Вы можете написать
int foo();
который сообщает компилятор foo
является функцией, возвращающей int
, но не какие параметры он принимает. Затем вы становитесь ответственным за то, чтобы получить право, потому что компилятор не может проверить.
Объявление extern
- будь то функция или переменная - уведомляет компилятор о символе и его типе и говорит, что определение будет предоставлено другим модулем. Компилятор оставляет заполнитель для компоновщика для заполнения позже.
Если вы посмотрите на Getopt (3) человек страницы, к примеру, вы увидите optarg
объявлен extern
; он определен в библиотеке времени выполнения C, но вы можете использовать его, потому что он был объявлен.
Теперь мы подошли к компоновщику и extern "C"
C++.
К компоновщику модуль предоставляет символы. Глобальные переменные и функции, не объявленные static
, имеют внешнюю связь, что означает, что они могут использоваться другими модулями.
В C есть соответствие 1: 1 между именами функций и внешними символами. Это символ. Например, Getopt (3) имеет символ с тем же именем в стандартной библиотеке C, LIBC:
$ nm -g $(find /usr/lib/ -name libc.a) 2>/dev/null | grep 'T getopt'
0000000000001620 T getopt
0000000000000000 T getopt_long
0000000000000040 T getopt_long_only
В C++ имя не символ. Функция C++ может быть перегружена; одно и то же имя может представлять разные функции с различными параметрами. Компилятор создает символ, который кодирует типы параметров. Сравните:
$ echo 'int foo(int foo) { return foo * foo; }' > a.c && cc -c a.c && nm a.o
0000000000000000 T foo
$ echo 'int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm a.o
0000000000000000 T _Z3fooi
Кодирование имени символа часто называют имя коверкая. нм (1) имеет функцию декодирования:
$ echo 'int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm -C a.o
0000000000000000 T foo(int)
Обратите внимание, что тип параметра отображается рядом с именем.
В C++ extern "C"
объявляет или определяет функцию как функцию C. Вот определение:
$ echo 'extern "C" int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm a.o
0000000000000000 T foo
В заявлении он сообщает компилятору, что функция определена в другом месте, и использования символ C.
В определении указано компилятору emit символ C, т. Е. Не изменяет имя, чтобы эта функция могла использоваться другими модулями C.
Я надеюсь, что ответит на ваш вопрос.
Функции 'extern' по умолчанию, вы можете использовать или опустить это ключевое слово из прямого объявления, как хотите, значение не изменяется. –
@ н.м. используя extern, компилятор игнорирует подпись, я имею в виду, что проверка типов не выполняется. Поэтому он не должен использоваться, когда это не требуется. – Bhargav
"компилятор игнорирует подпись" Неправильно. Кто вам сказал? –