2013-08-09 1 views
6

Я не могу понять, почему это не работает.Порядок определения `static` и` extern declaration` в единицах перевода

extern int i; 

int main() 
{ 
    printf(" %d ", i); 
} 

static int i =3; 

Кроме того, это не работает:

extern int i; 

static int i =3; 

int main() 
{ 
    printf(" %d ", i); 
} 

Но если static переменная определена перед extern declaration она работает:

static int i =3; 

extern int i; 

int main() 
{ 
    printf(" %d ", i); 
} 

Как я понимаю из extern int i говорит, что i является настоящее время где-то в другом месте и вот, как это выглядит (int i)

Но где-то еще средства:

1) Может быть, позже точка в блоке same перевода как global variable.

2) Возможно, в каком-то other переводческом подразделении.

Я думал, что (1) будет действителен, хотя static int i = 3 ограничил область видимости до текущей единицы перевода, где она определена.

Это не static int i =3global (я имею в виду, что это видно в единицах перевода), хотя он имеет ограниченную область действия для своей единицы перевода? Тогда почему компилятор не может его найти?

Когда я компилирую первые две версии, которые я получаю следующую ошибку компиляции времени:

error: static declaration of ‘i’ follows non-static declaration 
note: previous declaration of ‘i’ was here 

Я не могу понять, это сообщение об ошибке. Кроме того, почему он жалуется на статику declaration, а не definition?

+0

Что именно "не работает"? Это проблема компиляции? Вопрос времени выполнения? Я компилирую ваш код с VS 2010 и, похоже, работает правильно. – Nbr44

+0

GCC comipler, я получаю ошибку времени компиляции, статическое объявление i следует за нестатической декларацией. –

ответ

6

C11 6.2.2 Взаимосвязи идентификаторов Раздел 4

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

Так вторая декларация будет следовать первым, обратно в ваших примерах, первый и второй пример i будет иметь extern хранения класса. Компилятор считает, что это ошибка.

В то время как в третьем примере i будет static, потому что сначала отображается static. Это не должно быть проблемой.

И в разделе 7 документа C11 6.2.2 Взаимосвязи идентификаторов

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

Так что лучше не объявлять ту же переменную как с static и extern в одной и той же единице трансляции.

+0

Да, я согласен. Но меня беспокоит то, что почему '' '' '' '' '' всегда работает? Во многих компиляторах. –

+0

@UchiaItachi: Почему вы беспокоитесь о третьей версии? Этот ответ цитирует текст из стандарта C, который объясняет это: когда декларация 'extern' следует декларации с внутренней (' static') или внешней связью, используется предварительное объявление. –

+0

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

2

Ну, переменная либо extern, либо static. Помните, что static на глобальном уровне ограничивает его видимость только текущей единицей перевода, тогда как extern диктует, что он отображается на разных единицах перевода.

+0

Я знаю, что 'static' rescrits видимость и' extern' может передавать через другие единицы перевода 'включая 'текущий. Но код работает, если я определяю статическую переменную раньше и даю объявление extern, доказывающее, что у него есть 'static' и' extern'. –

+0

На самом деле это действительно меня озадачило, но мое единственное объяснение - это само сообщение об ошибке: 'статическое объявление 'i' следует за нестатической декларацией'. Насколько я понимаю, 'static' должен предшествовать любой нестатической декларации. И к тому времени, когда достигнут «extern», уже существует определение «i», которым «extern» доволен. – Nobilis

0

Нет смысла объявлять что-то static и снова как extern. Это не определено, поэтому не делайте этого.

+0

Но не потому, что декларация 'extern' есть? Говорить, что он определен дальше по файлу? И я знаю, что ваш код работает, как я уже упоминал в моем вопросе. –

+0

@UchiaItachi, отредактировал мой ответ, сейчас это правильно. Это неопределенное поведение. –

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