このコードにより、コンパイル エラー「エラー: 'p' が別の型で再定義されています」が発生します。
void fun() {
printf("fun");
}
void (*p)();
p = &fun;
しかし、 に変更すれば
void (*p)(); p = &fun;
、
void (*p)() = &fun
すべて OK です。
void (*p)(); p = &fun;
とはどう違い
void (*p)() = &fun
ますか?
このコードにより、コンパイル エラー「エラー: 'p' が別の型で再定義されています」が発生します。
void fun() {
printf("fun");
}
void (*p)();
p = &fun;
しかし、 に変更すれば
void (*p)(); p = &fun;
、
void (*p)() = &fun
すべて OK です。
void (*p)(); p = &fun;
とはどう違い
void (*p)() = &fun
ますか?
グローバル スコープで任意の割り当てを実行することはできません。試す:
void fun() {
printf("fun");
}
void (*p)();
int main(void) {
p = &fun;
return 0;
}
void (*p)() = &fun;
変数を作成して初期化しているため、機能します。初期化はグローバル スコープで許可されます。void (*p)(); p = &fun;
初期化されていない変数を作成し、それに値を割り当てます。割り当ては初期化とは異なる方法で処理され、一部の関数内で実行する必要があります。
void (*p)(); // This is a declaration
と
void (*p)() = &fun; // This is also a declaration
宣言です。
p = &fun; // This is a statement
は声明です。ステートメントは宣言ではありません (宣言はステートメントではありません)。
ファイル スコープでステートメントを使用することはできません。C では、ブロック スコープでのみステートメントを使用できます。
グローバル スコープでは、宣言と関数定義のみが有効です。割り当てはありません。
違いは、int n = 1;
初期化を伴う宣言であるのに対してn = 1;
、代入であることです。前者はグローバル スコープで有効ですが、後者は有効ではありません。関数ポインタについても同様です。
原則として、割り当てよりも初期化を常に優先する必要があり、それで問題が解決します。
void fun() { /* ... */ }
void (*p)() = &fun; // declaration, definition and initialization of "p"
前の 3 つの回答は質問に答えていません。「p = &fun;」を示している場合は正しくありません。課題です。
実際、コンパイラは「p = &fun;」を解釈しようとしています。"p" は宣言子、"&fun" は初期化子、"p = &fun" は init-declarator (C 仕様の正式な文法) を形成します。
これを宣言として解釈すると、宣言に含める必要がある型はデフォルトで int になるため (従来の理由から)、コンパイラは基本的にこれを「int p = &fun;」、つまり p の定義と見なします。p は以前に関数へのポインタとして定義されていたため、コンパイラは p を別の型で再定義していると警告します。
言語文法の専門家向け: これがどのようにして形式文法の宣言になるのか、私にはわかりません。translation-unit は external-declaration に展開され、external-declaration は宣言に展開され、宣言は「declaration-specifiers init-declarator-list[opt];」に展開されます。(C 標準の 6.7 あたり)。宣言指定子には、ストレージ クラス指定子、タイプ指定子、タイプ修飾子、または関数指定子に含まれるキーワードの少なくとも 1 つが必要なようです。そのようなキーワードはソースに表示されないため、これは宣言ではありません。コンパイラが 1999 年標準より前の文法で構文解析していると思われるため、これは従来の動作です。それにもかかわらず、エラー メッセージは、コンパイラが 2 つの定義を認識したことを明確に示しています。