関数宣言と変数宣言では話が違います。
関数宣言の省略時解釈は extern つまり外部結合ありです。
関数定義においても省略時解釈は extern つまり外部結合ありです。
関数定義と関数宣言とでは書式が違うので誤解を生む余地が無く、問題は発生しません。
大域変数の「定義にならない宣言」の場合は extern が必須です。
extern を書かずに大域変数を宣言し、初期化子が無い場合
・C の場合:変数の仮定義となります。仮定義は複数個あってかまいません。
・C++ の場合:変数の定義となります。定義は1つしか許されません。
・C/C++ とも、その大域変数は外部結合となります。
--a.c--
extern int g; /* 定義にならない宣言 */
int g; /* 仮定義 */
int g=1; /* 定義 */
C の場合、言語規格は
「同一翻訳単位中に同一名称の大域変数の複数個の仮定義がある」ことを認めています。
「複数翻訳単位中に同一名称の大域変数の定義がある」ことは定めておらず、
たいていの処理系では全翻訳単位での定義を1つにまとめてしまいます。
==b.cpp==
extern int g; /* 定義にならない宣言 */
int g; /* 定義 */
int g=1; /* 再定義:エラー */
C++ の場合、仮定義などというものはないので
「同一翻訳単位中に同一名称の大域変数の複数個の定義がある」
「複数翻訳単位中に同一名称の大域変数の複数個の定義がある」
の両方が言語規格上、認められずエラー発生となります。
http://www2s.biglobe.ne.jp/~hig/q_a/Programing_QA02.html