2015-09-12 1 views
2

Следующий фрагмент кода работает отличноПочему класс хранения «extern» работает по-разному в функциях?

extern int i; 
int i; 

int main(){ 
    return 0; 
} 

Вот что я получил есть «я» объявляется, а затем определены. Поскольку существует только одно определение, так что это прекрасно.

int main(){ 
    extern int i; 
    int i; 
    return 0; 
} 

Теперь, выше один дает следующее сообщение об ошибке

new.cpp: In function ‘int main()’: 
new.cpp:5:6: error: redeclaration of ‘int i’ 
    int i; 
    ^
new.cpp:4:13: note: previous declaration ‘int i’ 
    extern int i; 

Что здесь проблема? Здесь также существует одно определение «i».

ответ

3

Чтобы понять разницу, вы должны ознакомиться с концепцией под названием предварительное определение в С. процитировать стандарт C:

С11, проект, §6.9. 2, внешний объект определения

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

Что вы имеете в первом фрагменте лишь предварительное определение i. Вы можете иметь столько предварительных определений для объекта, сколько хотите (но допускается только одно определение):

int i; // tentative definition 
int i; // tentative definition 
int i; // tentative definition 

int main(void) { 
    return 0; 
} 

действителен.

У i Внешняя связь и предварительная установка. Если i определено где-то в одной и той же единицы перевода, то это будет фактическое определение i.Если нет другого определения i не найден в ЕП, то это становится полное определение, как если бы оно было определено как:

int i = 0; 

int main(void) { 
    return 0; 
} 

Но второй фрагмент int i; является не предварительное определение. Только объекты с внешней связью могут быть определены ориентировочно. Во втором фрагменте декларация extern int i; говорит, что i определен в другом месте с внешней связью. Но следующая строка int i; говорит, что i определен без привязки (локальные автоматические переменные не имеют связи - это не условное определение). Таким образом, существует конфликт определения для i. Следовательно, первый фрагмент отлично, а второй - нет.

+0

первый раз я столкнулся с словом «предварительное определение». Я работаю на C++, и я не думаю, что такая вещь существует. – cbinder

+1

Да, C++ не имеет предварительных определений. –

+0

век живи, век учись –

0

Во втором случае есть два объявления i в одном объеме. Один говорит: «существует переменная i, определенная вне этой функции»; другой говорит: «существует переменная i, определенная внутри этой функции». Без новой области это не допускается.

Правила различаются внутри и снаружи.

Обратите внимание, что вы можете использовать:

#include <stdio.h> 

int i = 21; 

int main(void) 
{ 
    extern int i; 
    i = 37; 
    { 
    int i = 57; 
    printf("%d\n", i); 
    } 
    printf("%d\n", i); 
    return 0; 
} 

компилируется нормально (если не включать -Wshadow в параметрах компиляции при использовании GCC или Clang), и производит 57 и 37 на выходе (как указывает CoffeeAndCode в comment).

Смотрите также How do I use extern to share variables between source files?

+0

следует добавить, что этот пример напечатал бы '57', а затем' 37' – CoffeeandCode

Смежные вопросы