2016-06-28 10 views
2

Я прошел через следующие вопросы:если глобальная переменная имеет внешнюю связь по умолчанию, то почему мы не можем получить доступ к ней напрямую в другом файле?

Выше ссылки описывают, что если определить глобальную переменную в одном файле и не указано ключевое слово extern они будут доступны в другой исходный файл из-за единицы перевода.

Теперь у меня есть file1.c в том, что определили следующие глобальной переменной и функции:

int testVariable; 

void testFunction() 
{ 
    printf ("Value of testVariable %d \n", testVariable); 
} 

В file2.c имеют следующий код

void main() 
{ 
    testVariable = 40; 
    testFunction(); 
} 

Теперь я получаю error: 'testVariable' undeclared (first use in this function) - почему?

Примечание: оба файла используются в одной программе с использованием make-файла.

Согласно моему пониманию, функция и глобальная переменная имеют внешнюю связь по умолчанию. Таким образом, мы можем напрямую использовать его имя в другом файле, но переменная не может быть причиной?

У кого-нибудь есть идея?

EDIT:

С ниже ответ я получаю идею, что, как в случае функции старого компилятора догадается и добавить неявную декларацию, но в случае переменной не может. Также C99 удалены неявное объявление, но до сих пор я получаю предупреждение в режиме C99, как:

warning: implicit declaration of function ‘testFunction’. 

Теперь пошли через ссылку ниже:

implicit int and implicit declaration of functions with gcc compiler

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

Но почему в случае переменной он не может обрабатываться дальше? Даже в случае функции, если компилятор работает, и если фактическое определение не существует, то при времени соединения оно не будет выполнено. Итак, какая польза для продвижения вперед?

+0

Если компилятор считать, что каждая необъявленная переменная была 'extern' объект, вы никогда не могли бы получить предупреждения о недостающих деклараций.Кроме того, как компилятор узнает, какой тип объектов имеет объект? – EOF

+0

@EOF то как работает компилятор в случае функции? – user2520119

+0

В старых C-стандартах существует понятие * неявного описания функции *. Он удаляется из более новых стандартов и его следует избегать. Возможно, вы захотите скомпилировать с помощью опции-компилятора использовать современный C-стандарт и предупреждения. – EOF

ответ

0

Когда компилятор справляется с file2.c, он ничего не знает о существовании testVariable и о его типе. И в результате он не может генерировать код для взаимодействия с таким объектом. И цель линии как

extern int testVariable; 

это позволить компилятору знать, что где-то такой объект существует и имеет тип int. С функциями мы не имеем такой проблемы из-за следующего правила - если функция не определена - компилятор предполагает, что она где-то определена как

int testFunction() { ... } 

Таким образом, вы можете передать любое количество аргументов к нему и попытаться получить int возвращаемое значение. Но если действительная сигнатура функции отличается - вы получите неопределенное поведение во время выполнения. Из-за этой слабости такой подход считается плохой практикой, и перед любым вызовом этой функции вы должны объявить прототип надлежащей функции.

+0

Так что же полезно добавить внешнюю привязку по умолчанию к глобальной переменной, хотя нам нужно написать ключевое слово extern для доступа в другом файле? – user2520119

+0

Нет преимуществ ИМО. И привязка по умолчанию не имеет ничего общего с требованиями объявлять используемые объекты верхнего уровня в каждой единицы перевода. – Sergio

+0

@ user2520119 Нет никаких преимуществ. Язык мог быть определен таким образом, чтобы внутренняя связь была по умолчанию, когда нет других спецификаторов, но, конечно, это не было определено так. Обычная практика заключается в том, чтобы поместить внешние объявления в общий файл '.h'' include_d всеми файлами '.c', которые ссылаются на них. –

7

Есть две вещи в игре здесь: Во-первых, есть разница между определением и декларации. Другое дело - концепция translation units.

Определение - это то, что определяет переменную, это фактическое место, где существует переменная, где компилятор резервирует пространство для переменной.

Для компилятора требуется объявление, чтобы знать, что существует символ где-то. Без объявления компилятор не знает, что символ существует.

Модуль перевода в основном и очень упрощен исходный файл плюс все его включенные заголовочные файлы. Объектный файл представляет собой единую единицу перевода, и компоновщик принимает все единицы перевода, чтобы создать окончательную программу.

Теперь у программы может быть только одно определение, например, глобальная переменная может существовать только в одной единице перевода или вы получите множественные ошибки определения при связывании. С другой стороны, декларация может существовать в любом количестве единиц перевода, компилятор будет использовать ее, чтобы сообщить компоновщику, что перевод ссылается на определение в другой (неизвестной в момент компиляции) единицы перевода.

Так что здесь происходит, что у вас есть определение и объявление в file1.c. Этот исходный файл используется как вход для одной единицы перевода, а компилятор создает для него один файл объекта, например file1.o. В другом исходном файле file2.c нет определения и никакого объявления глобальной переменной testVariable, поэтому компилятор не знает, что он существует и предоставит вам ошибку. Вы должны объявить это, например, делая

extern int testVariable; // This is a declaration of the variable 

Это немного сложнее для функции, так как в более ранних версиях стандартной C не должны объявлять функции используются, компилятор угадать и добавить неявное объявление. Если определение и неявное объявление не совпадают, это приведет к неопределенным поведением, поэтому неявные декларации функций были удалены в стандарте C99. Таким образом, вы действительно должны объявить функцию тоже:

void testFunction(void); // Declare a function prototype 

Обратите внимание, что extern ключевого слова здесь не требуется, потому что компилятор может автоматически сказать, что это объявление прототипа функции.

Полный file2.c должен выглядеть следующим

extern int testVariable; // This is a declaration of the variable 

void testFunction(void); // Declare a function prototype 

void main() 
{ 
    testVariable = 40; 
    testFunction(); 
} 
+2

Не является ли объявление 'int testVariable' в' file1.c' a * предварительным * определением? – EOF

+0

поэтому компилятор C99 также даст ошибку в функции? – user2520119

+1

'void main()' должен быть 'int main (void)'. Но да, это было неправильно и в оригинальном коде! –

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

  • Нет связанных вопросов^_^