почему функции не нужен внешний вид, а переменная нужна

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

a.cpp

#include <iostream>

using namespace std;

void funcfoo(){
    cout << "test only" << endl;
}

int varfoo = 10;



b.cpp

#include <iostream>

using namespace std;

extern void funcfoo();

extern int varfoo;

int main(){

    funcfoo();

    cout << varfoo;

    return 0;
}

Затем я скомпилирую это так: "cl b.cpp a.cpp"

Мой вопрос. Почему, когда я удаляю ключевое слово extern перед void funcfoo(), все работает нормально, но когда я удаляю ключевое слово extern перед int var foo, я получаю сообщение об ошибке?


person user1628256    schedule 27.08.2012    source источник
comment
См. stackoverflow.com/questions/2604202/ -- по умолчанию функции имеют внешнюю связь; ключевое слово лишнее.   -  person Wooble    schedule 27.08.2012


Ответы (4)


Вопрос в том, что означает каждая из строк кода. int varfoo — это определение переменной, а void funcfoo() — только объявление. Вы можете предоставить несколько объявлений объекта, но только одно определение. Синтаксис предоставления объявления и только объявления переменной заключается в добавлении ключевого слова extern: extern int varfoo; является объявлением.


3.1 [basic.def]/2 Объявление является определением, если только оно не объявляет функцию без указания тела функции (8.4), оно не содержит спецификатор extern (7.1.1) или спецификацию связывания25 (7.5) и не содержит ни инициализатора, ни функциональное тело [...]

person David Rodríguez - dribeas    schedule 27.08.2012
comment
Я думаю, что определение похоже на int varfoo = value;, затем int varfoo; декларация. Я ошибаюсь? - person user1628256; 27.08.2012
comment
интервал варфу; ‹--- Я думаю, что это декларация, а не определение - person user1628256; 27.08.2012
comment
@ user1628256: Да, ты. int varfoo; — определение без инициализации, int varfoo = value; — определение с инициализацией. - person David Rodríguez - dribeas; 27.08.2012
comment
интервал varfoo = значение; ‹---- Я думаю, что это объявить, а затем определить. Я ошибся? - person user1628256; 27.08.2012
comment
@ user1628256 int var; ‹-- (определение), var = 5; ‹-- определение - person 0x499602D2; 27.08.2012
comment
void funcfoo(){ cout ‹‹ только тест ‹‹ endl; } ‹--- это правильное определение? - person user1628256; 27.08.2012
comment
Это определение. Примечание: в глобальной области видимости int varfoo; с инициализацией. - person Karoly Horvath; 27.08.2012
comment
@KarolyHorvath: я не уверен в этом. Переменные со статической продолжительностью хранения инициализируются значением до любой другой инициализации, но это не означает, что объявление имеет инициализатор (у него его нет). - person David Rodríguez - dribeas; 27.08.2012
comment
так что нет объявления переменной только функция? - person user1628256; 27.08.2012
comment
@ user1628256: extern int varfoo; является объявлением переменной. - person David Rodríguez - dribeas; 27.08.2012
comment
хорошо, давайте просто забудем о extern, скажем, у нас есть только 1 файл .cpp .... так что int varfoo вы сказали, что это определение, верно? - person user1628256; 27.08.2012
comment
@ user1628256: Да, int varfoo; — это определение - person David Rodríguez - dribeas; 27.08.2012
comment
@David: почему extern int varfoo; становится декларацией? - person user1628256; 27.08.2012
comment
@ user1628256: Потому что так звучит язык ... прочитайте цитату из стандарта в ответе. - person David Rodríguez - dribeas; 27.08.2012
comment
@user1628256 user1628256 Прежде чем я отвечу на этот вопрос, не могли бы вы принять этот ответ, нажав на галочку рядом с ним? Это очень помогает. - person 0x499602D2; 27.08.2012
comment
@ user1628256: это действительно запутанно. Я чувствую, что у меня раздвоение личности (с другим Дэвидом). В любом случае: что вы не поняли из моего последнего комментария? Вы читали цитату из стандарта? - person David Rodríguez - dribeas; 27.08.2012
comment
@user1628256 user1628256 Вы знаете, что это объявление переменной, когда видите: int a;. Но это определение переменной, когда вы видите: a = 3 позже. Вы также можете сделать это: int a = 5;. Я определяю новую переменную с именем a, которую я инициализирую числом 5. Неважно, видите ли вы extern впереди. Если он не инициализируется, это объявление. - person 0x499602D2; 27.08.2012
comment
@david Я понимаю объявление и определение с помощью функции. Цитата из стандарта, который вы публикуете, касается функций, верно? Чего я не понимаю, так это переменной, которую вы сказали, что int varfoo - это определение, а extern int varfoo - это объявление. Я не понимаю, почему с extern это становится декларацией. - person user1628256; 27.08.2012
comment
@ user1628256: Нет, речь идет об объявлениях в целом. Обратите внимание, что последнее процитированное предложение содержит: и ни инициализатор, ни тело функции. Вы не можете предоставить initailizer для функции, так как вы не можете предоставить тело функции для переменной. - person David Rodríguez - dribeas; 27.08.2012
comment
@david int varfoo - это определение переменной ‹ --- вы сказали это - person user1628256; 27.08.2012
comment
@user1628256: Да, int varfoo; является определением и объявлением. extern int varfoo; — это декларация, но не определение. Вы спрашиваете одно и то же снова и снова, но я не понимаю, что вас смущает. - person David Rodríguez - dribeas; 27.08.2012
comment
@david Я уже знаю, что простой ответ на мой вопрос: имена функций по умолчанию видны компоновщику. Но я запутался с этим определением и объявлением. - person user1628256; 27.08.2012
comment
Пожалуйста, перенесите этот разговор в чат. -- chat.stackoverflow.com/rooms/10 Или создайте свой собственный - person 0x499602D2; 27.08.2012
comment
вы сказали в; является объявлением, а затем a = 3 является определением. Почему int varfoo - это определение, у которого нет значения. - person user1628256; 27.08.2012
comment
@ user1628256: Вы путаете меня (Дэвида Родригеса) с кем-то другим (Дэвидом). Я никогда не говорил, что int a; является декларацией (это так, но это также и определение). - person David Rodríguez - dribeas; 27.08.2012
comment
@david Вы знаете, что это объявление переменной, когда видите: int a;. Но это определение переменной, когда вы видите: a = 3 позже ‹-- исходит от вас - person user1628256; 27.08.2012
comment
@david хорошо, хотя я этого не понимаю, я хочу поблагодарить тебя. Сейчас я сонный, так что, может быть, это одна из причин, почему я этого не понимаю. - person user1628256; 27.08.2012
comment
@ user1628256: Игнорируйте весь этот комментарий (обратите внимание, что имя комментатора — «Дэвид» — без фамилий в конце...) Это вводит в заблуждение. int a является определением независимо от = 3. Это объявление, а не определение тогда и только тогда, когда присутствует extern и отсутствует инициализатор. - person David Rodríguez - dribeas; 27.08.2012
comment
@KarolyHorvath: вопрос касался комментария Примечание: в глобальной области видимости int varfoo; с инициализацией. Существует небольшая разница между наличием инициализатора и инициализируемой переменной. Переменная со статической продолжительностью хранения будет инициализирована значением независимо от наличия инициализатора. Объявление int varfoo; на уровне пространства имен не содержит инициализатора, даже если он гарантированно будет инициализирован 0. - person David Rodríguez - dribeas; 27.08.2012
comment
@David Rodríguez - dribeas: ughmmhuhvomit.. Я думаю, вы говорите то же самое, но с правильной терминологией. Спасибо. - person Karoly Horvath; 28.08.2012

Когда вы удаляете extern из extern void funcfoo();, вы заранее объявляете его, поэтому код ниже будет знать, что такое funcfoo(). Если бы вы сделали это с переменной, вы бы фактически создали ее экземпляр и столкнулись бы с другим вашим файлом. Следовательно, extern говорит: «Он существует, поверьте мне;)», что он разрешается из вашего другого файла.

person MartyE    schedule 27.08.2012

Другой способ думать об этом состоит в том, что когда вы делаете int varfoo, память выделяется для хранения переменной, поэтому это одновременно и определение, и объявление, когда вы делаете int foo(), функция объявляется, но не определяется, поэтому память не выделяется. Для функций связь по умолчанию является внешней, поэтому ее удаление не имеет значения, но для переменной, если вы скажете extern int varfoo, компилятор не будет выделять для нее память - он будет считать, что переменная определена где-то еще.

person Vimal Buck    schedule 31.08.2012

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

http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

Спасибо

person nikhs    schedule 16.02.2014