внешнее использование ключевого слова - PullRequest
23 голосов
/ 28 июля 2011

У меня есть три программы, в которых я использую ключевое слово 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();
}

Ответы [ 9 ]

10 голосов
/ 28 июля 2011

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

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

7 голосов
/ 28 июля 2011

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

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

Правила:

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

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

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


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

My module1.cpp file:

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

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

My Header file globals.h:

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

#endif

Other module2.cpp файл:

#include globals.h

char SomeOtherFunc(void)
{
  AGLOBAL+=10; // ok cause its declared by globals.h
  // do more....
}
6 голосов
/ 28 июля 2011

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

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

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

5 голосов
/ 28 июля 2011

Ваш компилятор небрежный. Компилируя этот тривиальный вариант (включая заголовок и объявление 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.

$

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

2 голосов
/ 12 февраля 2012

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

2 голосов
/ 11 февраля 2012

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

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, поэтому не могу говорить о C. В C ++ даже мое решение будет жаловаться, но не будет выдавать ошибку.

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

2 голосов
/ 28 июля 2011

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

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

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

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

Справка:
C ++ Стандарт: 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 оба определения.

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

2 голосов
/ 28 июля 2011
int k;
extern int k = 10; 

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

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

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

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

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

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

1 голос
/ 30 июля 2011

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

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

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

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

...