関数宣言とプロトタイプの代替(K& R)C構文
質問
この C
構文の便利な点— 「K& R」スタイルの関数宣言を使用していますか?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
Visual Studios 2010betaでこれを作成できました
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
わかりません。この構文のポイントは何ですか?私は書くことができます:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
指定しているように見える唯一のものは、使用するパラメーターの数と戻り値の型です。型のないパラメータはちょっとクールだと思いますが、なぜそれと関数宣言子の後に int paranName
を許可するのですか?変です。
これはまだ標準Cですか?
解決
あなたが尋ねている質問は、1つではなく2つの質問です。これまでの返信のほとんどは、一般的なブランケット「これはK& Rスタイル」ですべてをカバーしようとしました。答えですが、実際にはその一部だけがK& Rスタイルと呼ばれるものと関係があります(何らかの方法でC言語全体を「K& Rスタイル」と見なさない限り:)
最初の部分は、関数 definition
で使用される奇妙な構文ですint func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
これは実際にはK&amp; Rスタイルの関数定義です。他の答えはこれをかなりよくカバーしています。実際、それほど多くはありません。構文は廃止されましたが、C99でも完全にサポートされています(C99の「暗黙のint暗黙のルール」を除く。つまり、C99では p2
の宣言を省略できません)。
2番目の部分は、K&amp; Rスタイルとはほとんど関係がありません。関数を&quot; swapped&quot;で呼び出すことができるという事実を参照します。引数、つまり、このような呼び出しではパラメーターの型チェックは行われません。これは、K&amp; Rスタイルの定義自体とはほとんど関係がありませんが、プロトタイプを持たない関数と関係があります。このように関数を宣言すると、Cで表示されます
int foo();
実際には、不明なタイプの不特定の数のパラメータを受け取る foo
関数を宣言します。次のように呼び出すことができます
foo(2, 3);
and as
j = foo(p, -3, "hello world");
など(アイデアが得られます);
適切な引数を持つ呼び出しのみが「動作」します; (他のユーザーが未定義の動作を引き起こすことを意味します)、しかし、その正確さを保証するのはあなた次第です。コンパイラーは、何らかの方法で正しいパラメーターの種類とその総数を魔法のように知っていても、誤ったものを診断する必要はありません。
実際、この動作はC言語の機能です。危険なものですが、それでも機能です。このようなことができます
void foo(int i);
void bar(char *a, double b);
void baz(void);
int main()
{
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();
}
i.e。 「多態性」に異なる関数タイプを混在させる型キャストなしの配列(ここでは、さまざまな関数型は使用できません)。繰り返しますが、この手法の固有の危険性は非常に明白です(使用したことは覚えていませんが、どこで役立つか想像できます)が、結局Cです。
最後に、回答の2番目の部分を最初の部分にリンクするビット。 K&amp; Rスタイルの関数定義を作成する場合、関数のプロトタイプは導入されません。関数タイプに関する限り、 func
の定義は func
を次のように宣言します
int func();
i.e。型もパラメーターの総数も宣言されていません。あなたの元の投稿では、「...」と言います...使用するパラメータの数を指定しているようです...&quot;。正式に言えば、そうではありません! 2つのパラメーターのK&amp; Rスタイルの func
定義の後、 func
を次のように呼び出すことができます
func(1, 2, 3, 4, "Hi!");
これで制約違反は発生しません。 (通常、高品質のコンパイラが警告を出します)。
また、時々見落とされがちな事実は
int f()
{
return 0;
}
は、プロトタイプを導入しないK&amp; Rスタイルの関数定義でもあります。それを「モダン」にするにはパラメータリストに明示的な void
を挿入する必要があります
int f(void)
{
return 0;
}
最後に、一般的な考えに反して、K&amp; Rスタイルの関数定義とプロトタイプ化されていない関数宣言の両方がC99で完全にサポートされています。前者は、正しく覚えていれば、C89 / 90から非推奨になりました。 C99では、最初に使用する前に関数を宣言する必要がありますが、宣言はプロトタイプである必要はありません。混乱は、一般的な用語の混同に起因するようです。多くの人は、関数宣言を「プロトタイプ」と呼びますが、実際には「関数宣言」と呼ばれます。 「プロトタイプ」と同じものではありません。
他のヒント
これはかなり古いK&amp; R C構文です(ANSI / ISO Cより前の日付です)。最近では、これをもう使用すべきではありません(すでにその大きな欠点に気付いているように、コンパイラは引数の型をチェックしません)。実際の例では、引数のタイプはデフォルトで int
になっています。
当時、この構文が使用されていたため、次のような関数が見つかることがありました
foo(p, q)
{
return q + p;
}
これは実際には有効な定義でした。 foo
、 p
、および q
の型はデフォルトで int
。
これは単に「ANSI C」よりも前の古い構文です。あなたがより精通しているかもしれない構文。通常、&quot; K&amp; RC &quot;と呼ばれます。
コンパイラは、もちろん完全であり、古いコードベースを処理できるようにサポートしています。
これは、1989年にCが標準化される前のオリジナルのK&amp; R構文です。C89は、C ++から借用した関数プロトタイプを導入し、K&amp; R構文を廃止しました。新しいコードで使用する理由はありません(使用しない理由はたくさんあります)。
これは、Cに関数のプロトタイプがなかった時代の遺物です。当時、(と思う)関数は int
を返すと想定され、その引数はすべて int
と想定されていました。関数パラメーターのチェックは行われませんでした。
現在のC言語で関数プロトタイプを使用する方がはるかに優れています。
そして、あなたは C99でそれらを使用する必要があります(C89は依然として古い構文を受け入れます)。
C99では、関数を宣言する必要があります(おそらくプロトタイプなしで)。新しい関数をゼロから作成する場合は、宣言を提供する必要があります...プロトタイプも作成する必要があります。何も失わず、コンパイラから追加のチェックを取得します。