Что касается второго вопроса, я хотел бы знать, почему!
Чтобы ответить на пункт 2, хранение объявлений в заголовочном файле помогает избежать ситуаций, подобных следующей.
Вы решаете, что вам нужно отслеживать своих цыплят в file.c
:
int number_of_chickens;
В file2.c
вы решаете, что было бы хорошей идеей представить числокуры как двойные вместо целых, но вы забыли обновить file.c
:
extern double number_of_chickens;
double count_chickens() {
return number_of_chickens;
}
void add_to_chickens(double how_many) {
number_of_chickens += how_many;
}
Это скомпилируется просто отлично.Линкер будет обрабатывать number_of_chickens
как имя, ссылающееся на 4-битное целое в file.c
и 8-битное двойное в file2.c
.
Если вы вызовете функцию count_chickens
, она вернет мусор (старшие 32 бита двойного будут заполнены содержимым int number_of_chickens
, младшие 32 бита будут неопределенными - что будет послеnumber_of_chickens
в памяти).
Еще хуже, когда вы вызываете add_to_chickens(1)
в file2.c
, вы записываете 8 байтов в 4-байтовое хранилище, что, безусловно, вызывает хаос, но не обязательно вызывает ошибку времени выполнения (по крайней мере, не сразу).
Если вы храните внешнюю декларацию в общем заголовочном файле, вы сразу получаете ошибку времени компиляции.Если вы этого не сделаете, вы получите необъяснимую нестабильность через 3 месяца после отправки.