С++ ключевое слово extern для функций. Почему нет просто включить заголовочный файл?
Если я правильно понимаю, это означает
extern void foo();
что функция foo объявлена в другой единицы перевода.
1) Почему не просто # включить заголовок, в котором объявлена эта функция?
2) Как линкер знает, где искать функцию при связывании времени?
edit: Возможно, мне следует пояснить, что после этого вышеприведенного объявления следует использовать функцию
foo();
В этой единицы перевода никогда не определяется.
Ответы
Ответ 1
1) Он может не иметь заголовочного файла. Но да, в общем, для больших проектов у вас должен быть заголовочный файл, если несколько единиц перевода будут использовать эту функцию (не повторяйте сами).
2) Линкер выполняет поиск по всем объектным файлам и библиотекам, о которых было сказано о поиске функций и других символов.
Ответ 2
Нет, это означает, что функция foo
объявляется с внешней связью. Внешняя связь означает, что имя foo
относится к одной и той же функции во всей программе. Где функция определена, не имеет значения. Он может быть определен в этой единице перевода. Он может быть определен в другой единицы перевода.
Использование ключевого слова extern
, как показано в вашем примере, является излишним. По умолчанию функции всегда имеют внешнюю связь. Вышеописанное на 100% эквивалентно просто
void foo();
Что касается компоновщика, когда компоновщик связывает программу вместе, она просто выглядит повсюду. Он просматривает все определения, пока не найдет определение для foo
.
Ответ 3
Как уже указывали другие, ключевое слово extern
используется для указания имени (переменной или функции) имеет внешнюю связь, то есть имя относится к одному и тому же объекту во всей программе. Кроме того, это значение по умолчанию для переменных и функций, определенных в области файлов, поэтому это использование является излишним.
Другое использование ключевого слова extern выглядит следующим образом:
extern "C" void foo();
Это означает, что функция foo
будет связана с использованием соглашений C для привязки (возможно, потому, что это функция, определенная в библиотеке C, или функция, предназначенная для вызова C-программами).
Ответ 4
Это уже означает, что без ключевого слова extern. По умолчанию функции имеют внешнюю связь, если вы не объявляете их статическими.
Использование прототипов функций в порядке, но легко получить это неправильно. Ошибка компоновщика, которую вы получите, не так легко диагностировать, когда вы переопределяете реализацию функции. Компилятор не знает, где искать, именно ваша задача - предоставить объектный файл, содержащий определение функции, чтобы он был счастлив.
Ответ 5
1) Я не знаю, зачем мне это нужно для функции. Может быть, кто-то еще может вмешаться.
2) Линкер определяет это, просматривая все объектные файлы и проверяя символы внутри каждого объектного файла. Я предполагаю, что в зависимости от вашего компоновщика точный порядок поиска может отличаться.
Для GNU binutils 'ld все объектные файлы и библиотеки, которые появляются в командной строке компоновщика после того, как объект, содержащий отсутствующий символ, просматриваются слева направо и выбирается первый найденный символ.
Пример 1:
- a.o - использует foo(), bar()
- liba - предоставляет bar()
- libb - предоставляет foo()
$ > ld a.o -la -lb
приведет к поиску a.o для символов undefined. После этого ld перейдет через библиотеки слева направо, чтобы найти эти символы, и найдет бар в liba и foo в libb.
Это может привести к возникновению странных проблем при круговых зависимостях:
Пример 2:
- a.o - использует bar()
- liba - предоставляет bar(), использует foo()
- libb - предоставляет foo(), использует bar()
Теперь существует циклическая зависимость между liba и libb, и связь не будет выполнена:
$ > ld a.o -la -lb
потому что при поиске через undefined символов в libb ld определит, что нет другого lib справа от -lb, который предоставляет этот символ. Это может быть исправлено, по крайней мере, двумя способами:
1) ссылка liba дважды:
$ > ld a.o -la -lb -la
2) используйте функцию группировки ld
$ > ld a.o --start-group -la -lb -end-group
В случае 2) группировка сообщает ld для поиска по всем символам во всех библиотеках, принадлежащих этой группе.