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

Использование ключевого слова extern

У меня есть три программы, в которых я использую ключевое слово extern. Я не могу понять результат. Ниже приведены три примера:

Пример 1: Я ожидал, что ниже код даст ошибку компиляции, что несколько объявлений k. Но он отлично работает?

int k; //works fine
extern int k = 10;

void main()
{
    cout<<k<<endl;
    getchar();
}

Пример 2: Когда я пытаюсь инициализировать "k" в приведенном выше примере, компилятор дает ошибку. Почему?

int k = 20; //error
extern int k = 10;

void main()
{
    cout<<k<<endl;
    getchar();
}

Пример 3: В этом примере я изменил порядок определений, упомянутый в примере 1. Когда я компилирую этот код, я получаю ошибки. Почему?

extern int k = 10;
int k;   //error

void main()
{
    cout<<k<<endl;
    getchar();
}
4b9b3361

Ответ 1

Пример 2. Вы пытаетесь дважды инициализировать глобальную переменную двумя значениями. Это ошибка.

Пример 3. Сначала вы объявляете переменную extern, а затем определяете переменную с тем же именем в одном модуле компиляции. Это невозможно.

Ответ 2

Вы должны использовать ключевое слово **extern** так, как оно предназначено для использования, которое должно ссылаться на то, что выходит за пределы текущей области.

Вы также должны следовать правилам, которые работают в каждом компиляторе, а не пытаться использовать аномалии некоторого компилятора, ваши примеры дали мне много ошибок в моем собственном компиляторе.

Правила:

  • Используйте extern для ссылки, а не для определения переменной.

  • Используйте какое-то соглашение для внешнего именования. Я поместил все мои внешние строки в капители, поэтому, когда я вижу что-то вроде MYVAR, я знаю его глобальное.

  • Поместите все ваши внешние элементы в файл заголовка include (.h) и выполните #include в ваших файлах cpp, таким образом, это будет более удобно и поможет разблокировать исходный код.


Смотрите этот пример, где я использую все 3 правила:

Мой файл module1.cpp:

unsigned short int AGLOBAL = 10; // definer and initializer

void MyFunc(void)
{
  AGLOBAL+=1; // no need to include anything here cause is defined above
  // more .....    
}

Мой заголовочный файл globals.h:

// this is to include only once
#ifndef MYH
#define MYH
extern unsigned short int AGLOBAL; // no value in here!

#endif

Другой файл module2.cpp:

#include globals.h

char SomeOtherFunc(void)
{
  AGLOBAL+=10; // ok cause its defined by globals.h
  // do more....
}

Ответ 3

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

Переменная определяется извне.

Первая программа должна дать вам ошибку. Какой компилятор вы используете? BTW, void main() не является стандартным. Ни в C, ни в С++.

Ответ 4

Ваш компилятор неаккуратен. Компилируя эту тривиальную вариацию (включая заголовок и объявление using), я получаю:

$ cat xxx.cpp
#include <iostream>
using namespace std;

int k; //works fine
extern int k = 10;

void main()
{
cout<<k<<endl;
getchar();
}
$ g++ -c  xxx.cpp
xxx.cpp:5:12: warning: ‘k’ initialized and declared ‘extern’ [enabled by default]
xxx.cpp:5:12: error: redefinition of ‘int k’
xxx.cpp:4:5: error: ‘int k’ previously declared here
xxx.cpp:7:11: error: ‘::main’ must return ‘int’
$ g++ --version
g++ (GCC) 4.6.0
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$

Какой компилятор вы используете?

Ответ 5

int k;
extern int k = 10; 

Это нормально в C, где вы можете иметь "предварительное определение" в дополнение к реальному. В С++ это запрещено. Это попытка дважды объявить одну и ту же переменную.

Мой компилятор C также предупреждает меня, что наличие как extern, так и инициализация в то же время необычны.

int k = 20; //error
extern int k = 10;    

Это пытается дать k два разных значения, что, конечно, не работает.

extern int k = 10;
int k;   //error 

Это похоже на случай 1. Это не разрешено в С++, но представляется приемлемым в C99.

Ответ 6

Случай 1: Дает Ошибка переопределения в С++ (gcc-4.3.4)

Случай 2: Дает Ошибка переопределения в С++ (gcc-4.3.4)

Случай 3: Дает Ошибка переопределения в С++ (gcc-4.3.4)

Во всех трех случаях вы пытаетесь определить переменную с именем k с внешней привязкой, и вы пытаетесь определить другую переменную с именем k в той же области, это порождает ошибку переопределения.

Справка:
Стандарт С++: 3.1 Объявления и определения

3 [Example: all but one of the following are definitions:

int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x+a; } // defines f and defines x
......

В приведенном выше фрагменте a и c оба являются определениями.

Если ваш компилятор не дает вам ошибку для всех трех случаев, тогда он разбивается на С++.

Ответ 7

Для третьего вы действительно хотите этого

extern int k = 10;
extern int k;   //okay: this is just a declaration. 
// extern int k = 4;  re-define is no good.

void main()
{
cout<<k<<endl;
getchar();
}

Вы можете определить переменную только один раз. Однако вы можете объявлять столько раз, сколько хотите.


Чтобы указать бит далее, int i; является объявлением и определением. Часто временная интуиция рассматривается как "определение". Для автоматической переменной декларация и определение выполняются в одном заявлении.

Итак, когда мы определяем int k;, была выделена память, имя которой указано "k". Следовательно, компоновщик будет жаловаться, когда вы попытаетесь переопределить его.

int k;
extern int k = 3;  // already defined in the previous statement

Следовательно, это также ошибка компиляции

extern int k = 3;
int k;    // trying to redefine again - bad

Это, вероятно, применяется только в С++. Я не знаком с C, поэтому я не могу говорить о C. В С++ даже мое решение будет жаловаться, но не будет бросать на него ошибку.

Пожалуйста, судите меня и исправляйте мои ошибки. Я также изучаю.

Ответ 8

Я понимаю примеры 2 и 3. Но тот факт, что пример 1 был скомпилирован, настолько странный. gcc никогда не скомпилировал такой код.

Ответ 9

Сначала выберите нит. Вы говорите о глобальном разрешении переменных. Это задача компоновщика, а не компилятора. Хотя это не имеет реальных последствий, поскольку все компиляторы обычно выполняются вместе с компоновщиком.

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

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

Случай 1: У вас слабая декларация, за которой следует сильная. Это здорово. Случай 2: У вас есть две сильные заявления. Ошибка! Случай 3: У вас есть сильное выражение, за которым следует слабый. Я на самом деле не уверен, почему этот провал. Если бы я догадался, я бы сказал, что вторая декларация считается сильной компоновщиком.