Ключевое слово экстерна действительно необходимо?

...
#include "test1.h"

int main(..)
{
    count << aaa <<endl;
}

aaa определяется в test1.h, и я не использовал ключевое слово экстерна, но все еще могу сослаться aaa.

Таким образом, я сомневаюсь, extern действительно необходимый?

7
задан httpinterpret 15 May 2010 в 13:09
поделиться

5 ответов

Если aaa не определен в другом модуле компиляции, вам не нужен extern, иначе вы это сделаете.

1
ответ дан 6 December 2019 в 06:23
поделиться

Я обнаружил, что лучший способ организовать ваши данные - это следовать двум простым правилам:

  • Объявлять вещи только в файлах заголовков.
  • Определите вещи в файлах C (или cpp, но для простоты я буду использовать здесь только C).

Под объявлением я подразумеваю уведомить компилятор о существовании вещей, но не выделять для них хранилище. Сюда входят typedef , struct , extern и так далее.

По определению я обычно имею в виду «выделить место для», например int и так далее.

Если у вас есть такая строка, как:

int aaa;

в файле заголовка, каждая единица компиляции (в основном определяется как входной поток для компилятора - файл C вместе со всем, что он приносит с ] #include , рекурсивно) получит свою собственную копию. Это вызовет проблемы, если вы свяжете вместе два объектных файла, для которых определен один и тот же символ (за исключением некоторых ограниченных обстоятельств, таких как const ).

Лучший способ сделать это - определить переменную aaa в одном из ваших файлов C, а затем поместить:

extern int aaa;

в файл заголовка.

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

6
ответ дан 6 December 2019 в 06:23
поделиться

extern имеет свое применение. Но в основном это связано с «глобальными переменными», которые не одобряются. Основная идея extern заключается в том, чтобы объявлять вещи с внешней связью. Таким образом, это своего рода противоположность static. Но внешняя связь во многих случаях является связью по умолчанию, поэтому в этих случаях вам не нужен extern. Другое использование extern заключается в том, что он может превращать определения в объявления. Примеры:

extern int i;  // Declaration of i with external linkage
               // (only tells the compiler about the existence of i)

int i;         // Definition of i with external linkage
               // (actually reserves memory, should not be in a header file)

const int f = 3; // Definition of f with internal linkage (due to const)
                 // (This applies to C++ only, not C. In C f would have
                 // external linkage.) In C++ it's perfectly fine to put
                 // somethibng like this into a header file.

extern const int g; // Declaration of g with external linkage
                    // could be placed into a header file

extern const int g = 3; // Definition of g with external linkage
                        // Not supposed to be in a header file

static int t; // Definition of t with internal linkage.
              // may appear anywhere. Every translation unit that
              // has a line like this has its very own t object.

Видите ли, это довольно сложно. Существует два ортогональных понятия: связь (внешняя против внутренней) и вопрос о декларировании против определения. Ключевое слово extern может повлиять на оба.Что касается связи, то она противоположна static. Но значение static также перегружено и — в зависимости от контекста — контролирует или не контролирует связь. Другая вещь, которую он делает, - это контроль времени жизни объектов («статическое время жизни»). Но в глобальном масштабе все переменные уже имеют статическое время жизни, и некоторые люди подумали, что было бы неплохо переработать ключевое слово для управления связью (это я просто догадываюсь).

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

13
ответ дан 6 December 2019 в 06:23
поделиться

Если ваш test1.h имеет определение aaa, и вы хотите включить файл заголовка в несколько единиц перевода, вы столкнетесь с множественной ошибкой определения, если aaa не является константой. Лучше вы определите aaa в файле cpp и добавьте определение extern в файл заголовка, который можно добавить в другие файлы в качестве заголовка.

Правило большого пальца для наличия переменной и константы в файле заголовка

 extern int a ;//Data declarations
 const float pi = 3.141593 ;//Constant definitions

Поскольку константа имеет внутреннюю связь в C ++, любая константа, определенная в единице перевода, не будет видна для другой единицы трансляции, но это не относится к переменной, которую они имеют внешнюю связь, т. е. видны другим единицам перевода. Помещение определения переменной в заголовок, который используется в другой единице перевода, приведет к множественному определению переменной, что приведет к множественной ошибке определения.

5
ответ дан 6 December 2019 в 06:23
поделиться

В этом случае extern не требуется. Extern необходим, когда символ объявлен в другом модуле компиляции.

Когда вы используете директиву предварительной обработки #include , включенный файл копируется вместо директивы. В этом случае вам не нужно extern , потому что компилятор уже знает aaa .

3
ответ дан 6 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

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