関数宣言はプロトタイプではありません

C int foo() で と int foo(void) 異なる機能です。 int foo() int foo(void) の間、任意の数の引数を受け入れます 0 の引数を受け入れます。 C++ では、同じことを意味します。 void を使用することをお勧めします 議論がないことを意味するときは一貫して。

変数 a がある場合 、 extern int a; a であることをコンパイラに伝える方法です。 別の翻訳単位に存在する可能性のあるシンボル (C コンパイラはソース ファイルを表す) であり、リンク時まで解決しないでください。一方、関数名であるシンボルは、とにかくリンク時に解決されます。関数のストレージ クラス指定子の意味 (externstatic ) 可視性と extern のみに影響します がデフォルトなので、extern

extern を削除することをお勧めします 、それは無関係であり、通常は省略されます。


簡単な答え:int testlib() を変更してください int testlib(void) へ 関数が引数を取らないことを指定します。

プロトタイプ 定義上、関数の引数の型を指定する関数宣言です。

のような非プロトタイプ関数宣言
int foo();

引数の数や型を指定しない古いスタイルの宣言です。 (1989 ANSI C 標準より前では、これは言語で使用できる唯一の種類の関数宣言でした。) このような関数は任意の数の引数で呼び出すことができ、コンパイラは文句を言う必要はありません。呼び出しは 定義 と矛盾しています 、あなたのプログラムには未定義の動作があります。

1 つ以上の引数を取る関数の場合、宣言で各引数の型を指定できます。

int bar(int x, double y);

引数のない関数は特殊なケースです。論理的には、空の括弧は引数を指定する良い方法ですが、その構文は古いスタイルの関数宣言で既に使用されていたため、ANSI C 委員会は void を使用して新しい構文を発明しました。 キーワード:

int foo(void); /* foo takes no arguments */

関数の定義 (関数が実際に行うことのコードを含む) は 宣言 も提供します .あなたの場合、次のようなものがあります:

int testlib()
{
    /* code that implements testlib */
}

これは testlib の非プロトタイプ宣言を提供します .定義として、これはコンパイラに testlib を伝えます。 パラメーターはありませんが、宣言として、コンパイラーに testlib を伝えるだけです 特定されていないが固定の数と型の引数を取ります。

() を変更すると (void) まで 宣言はプロトタイプになります。

プロトタイプの利点は、誤って testlib を呼び出した場合 1 つ以上の引数を指定すると、コンパイラはエラーを診断します。

(C++ には少し異なる規則があります。C++ には古いスタイルの関数宣言がありません。空の括弧は、関数が引数を取らないことを明確に意味します。C++ は (void) をサポートしています ただし、コードを C と C++ の両方としてコンパイルする必要がある場合を除き、おそらく () を使用する必要があります。 C++ と (void) で C の構文)


試してみてください:

extern int testlib(void);