Подтвердить что ты не робот

С++ ключевое слово extern для функций. Почему нет просто включить заголовочный файл?

Если я правильно понимаю, это означает

extern void foo();

что функция foo объявлена ​​в другой единицы перевода.

1) Почему не просто # включить заголовок, в котором объявлена ​​эта функция?

2) Как линкер знает, где искать функцию при связывании времени?

edit: Возможно, мне следует пояснить, что после этого вышеприведенного объявления следует использовать функцию

foo();

В этой единицы перевода никогда не определяется.

4b9b3361

Ответ 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 для поиска по всем символам во всех библиотеках, принадлежащих этой группе.