я, возможно, скажу слегка не так, как говорят всякие гранды Си, потому что люблю сам для себя формулировать определения наиболее понятно и непротивречиво.
так вот. каждый элемент программы в Си может иметь:
1. объявление или описание
2. определение или реализация
3. использование
объявление - это информация компилятору о наличии некоей сущности с характерными свойствами. для переменной - это ее тип, для функции кроме типа еще и типы ее параметров.
определение - это наполнение упомянутой сущности реальным смыслом. для переменной это присваивание начального значения, для функции - реализация ее тела.
использование - это, само собой, использование сущности в алгоритме.
объявление в общем случае является желательным, но необязательным. в частности, без прототипов функций можно вполне обойтись. для переменных определение и реализация могут совмещаться в одной строке, как уже было сказано. но принципиально это следует различать. объявления по-хорошему должны быть только в хидерах, в то время как реализация и использование - только в модулях. это правильная практика.
что касается
extern. объявление переменной с этим префиксом - правильный вариант для многофайловых проектов, он гарантирует, что при использовании одного хидера вы всегда будете иметь доступ к нужной переменной. тот факт, что при подключении хидера к модулю с реализацией этой переменной возникает как бы двойное описание - не проблема, это разрешено стандартом.
Код: Выделить всё
extern int var;
int var;
// тут нет никаких ошибок!
а вот попытка в хидере определить переменную - это крайне порочная практика, такая же, как подключение директивой include исходника на Си
#include "myfile.c".