Ключевое слово экстерна C++ на функциях. Почему не просто включают заголовочный файл?

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

extern void foo();

то, что функциональное нечто объявляется в другой единице перевода.

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

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

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

foo();

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

45
задан user199421 9 April 2010 в 00:13
поделиться

5 ответов

1) Может не иметь файла заголовка. Но да, как правило, для больших проектов у вас должен быть файл заголовка, если несколько единиц перевода собираются использовать эту функцию (не повторяйтесь).

2) Компоновщик просматривает все объектные файлы и библиотеки, о которых ему было сказано, чтобы найти функции и другие символы.

28
ответ дан 26 November 2019 в 21:21
поделиться

Нет, это означает, что функция foo объявлена ​​с внешней связью . Внешняя связь означает, что имя foo относится к одной и той же функции во всей программе. Не имеет значения, где определена функция. Его можно определить в этой единице перевода. Его можно определить в другой единице перевода.

Использование ключевого слова extern , как показано в вашем примере, излишне. По умолчанию функции всегда имеют внешнюю связь. Вышеупомянутое на 100% эквивалентно просто

void foo();

. Что касается компоновщика, когда компоновщик связывает программу вместе, он просто смотрит везде . Он просматривает все определения, пока не найдет определение для foo .

16
ответ дан 26 November 2019 в 21:21
поделиться

Как уже было сказано другими, ключевое слово extern используется, чтобы указать, что имя (переменная или функция) имеет внешнюю связь, то есть имя относится к одному и тому же объекту во всей программе. Кроме того, это значение по умолчанию для переменных и функций, определенных в области файла, поэтому такое использование излишне.

Существует еще одно использование ключевого слова extern, которое выглядит следующим образом:

extern "C" void foo();

Это означает, что функция foo будет связана с использованием соглашений C для связывания (возможно, потому что это функция, определенная в библиотеке C. или функция, предназначенная для вызова программами на языке C).

16
ответ дан 26 November 2019 в 21:21
поделиться

Это уже означает, что без ключевого слова extern. По умолчанию функции имеют внешнюю связь, если вы не объявляете их статическими.

Использование прототипов функций - это нормально, но легко ошибиться. Ошибка компоновщика, которую вы получите, не так легко диагностировать, когда вы переопределяете реализацию функции. Компоновщик не знает, где искать, ваша задача - предоставить ему объектный файл, содержащий определение функции, чтобы он оставался довольным.

8
ответ дан 26 November 2019 в 21:21
поделиться

1) Я не знаю, зачем мне это для функции. Может быть, вмешается кто-нибудь другой.

2) Компоновщик определяет это, просматривая все объектные файлы и проверяя символы внутри каждого объектного файла. Я предполагаю, что в зависимости от вашего компоновщика точный порядок поиска может отличаться.

Для GNU binutils ld все объектные файлы и библиотеки, которые появляются в командной строке компоновщика после объекта, содержащего отсутствующий символ, ищутся слева направо и выбирается первый найденный символ.

Пример 1:

  • ao - использует foo (), bar ()
  • liba - предоставляет bar ()
  • libb - предоставляет foo ()

$> ld ao -la - lb

приведет к поиску неопределенных символов в ao. После этого ld будет просматривать библиотеки слева направо для поиска этих символов и найдет bar в liba и foo в libb.

Это может привести к странным проблемам с циклическими зависимостями:

Пример 2:

  • ao - использует bar ()
  • liba - предоставляет bar (), использует foo ()
  • libb - предоставляет foo (), использует bar ()

Теперь существует циклическая зависимость между liba и libb, и связывание не удастся:

$> ld ao -la -lb

потому что при поиске неопределенных символов в libb, ld определит, что нет другой библиотеки справа от -lb , которая предоставляет этот символ. Это можно исправить как минимум двумя способами:

1) дважды связать liba: $> ld ao -la -lb -la

2) использовать функцию группировки ld $> ld ao --start-group -la -lb --end-group

В случае 2) группировка указывает ld на поиск по всем символам во всех библиотеках, принадлежащих этой группе.

2
ответ дан 26 November 2019 в 21:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: