Действительно ли необходимо ключевое слово extern? - PullRequest
6 голосов
/ 15 мая 2010
...
#include "test1.h"

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

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

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

Ответы [ 5 ]

12 голосов
/ 15 мая 2010

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 также перегружено и - в зависимости от контекста - контролирует или не контролирует связь. Другая вещь, которую он делает, это контролирует время жизни объектов («статическое время жизни»). Но в глобальном масштабе все переменные уже имеют статическое время жизни, и некоторые люди думали, что было бы неплохо перезапустить ключевое слово для управления связью (это я только догадываюсь).

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

7 голосов
/ 15 мая 2010

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

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

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

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

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

int aaa;

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

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

extern int aaa;

в вашем заголовочном файле.

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

5 голосов
/ 15 мая 2010

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

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

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

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

3 голосов
/ 15 мая 2010

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

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

1 голос
/ 15 мая 2010

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

...