Вам потрібно розрізнити два окремих поняття: визначення функції та оголошення символів. "extern" - це модифікатор зв'язку, натяк компілятору про те, де визначений символ, на який посилається згодом (підказка - "не тут").
Якщо я напишу
extern int i;
у області файлу (поза функціональним блоком) у файлі C, тоді ви говорите: "змінна може бути визначена в іншому місці".
extern int f() {return 0;}
є і оголошенням функції f, і визначенням функції f. Визначення в цьому випадку перегукує зовнішність.
extern int f();
int f() {return 0;}
спочатку декларація, а потім визначення.
Використання параметра extern
помилкове, якщо ви хочете оголосити та одночасно визначити змінну області файлу. Наприклад,
extern int i = 4;
видасть помилку або попередження, залежно від компілятора.
Використання extern
корисно, якщо ви прямо хочете уникати визначення змінної.
Дозволь пояснити:
Скажімо, файл ac містить:
#include "a.h"
int i = 2;
int f() { i++; return i;}
Файл ах включає:
extern int i;
int f(void);
а файл bc містить:
#include <stdio.h>
#include "a.h"
int main(void){
printf("%d\n", f());
return 0;
}
Зовнішній вигляд у заголовку корисний, оскільки він повідомляє компілятору під час фази посилання, "це декларація, а не визначення". Якщо я видаляю рядок у ac, який визначає i, виділяє для нього простір і присвоює йому значення, програма не може компілювати з невизначеною посиланням. Це говорить розробнику, що він посилався на змінну, але ще не визначив її. Якщо з іншого боку я опущу ключове слово "екстерн" і видаляю int i = 2
рядок, програма все-таки компілюється - я визначуся зі значенням за замовчуванням 0.
Змінні області файлу неявно визначаються зі значенням за замовчуванням 0 або NULL, якщо ви явно не призначите їм значення - на відміну від змінних блоків області, які ви оголошуєте у верхній частині функції. Ключове слово "екстерн" уникає цього неявного визначення і, таким чином, допомагає уникнути помилок.
Для функцій, у деклараціях функцій, ключове слово справді є зайвим. Оголошення функцій не мають неявного визначення.