関数宣言とプロトタイプの代替(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-style" として捉えていないのでしたら......ですが)。
最初の部分は、関数で使用される奇妙な構文 定義
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
これは実際にK&Rスタイルの関数定義です。他の回答がこれをかなりカバーしています。そして、実際にはそれほど多くのことはありません。この構文は非推奨ですが、C99でもまだ完全にサポートされています(C99の"no implicit int"ルールを除いて、つまり、C99では
p2
).
2番目の部分はK&Rスタイルとはあまり関係がありません。私は、関数が引数を入れ替えた状態で呼び出される可能性があるという事実を指しています。これは、K&Rスタイルの定義とはあまり関係がありませんが、プロトタイプを持たない関数には関係があります。C言語では、次のような関数を宣言します。
int foo();
は、実際には関数を宣言しています。
foo
を取る関数です。
型不明の不特定多数のパラメータをとる
. として呼び出すことができます。
foo(2, 3);
というように
j = foo(p, -3, "hello world");
といった具合です(おわかりになりますよね)。
適切な引数を持つ呼び出しだけが、quot;work" (つまり、他のものは未定義の動作を生成します) ですが、その正しさを保証するのは完全にあなた次第です。コンパイラーは、たとえ魔法のように正しい引数の型とその合計数を知っていたとしても、不正確なものを診断することは要求されません。
実際、この動作は 機能 であり、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]();
}
つまり、型キャストなしでquot;polymorphic"配列に異なる関数型を混ぜることができます(ただし、可変長関数型はここでは使えません)。繰り返しますが、この手法の本質的な危険性は非常に明白です(私はこれを使った記憶がありませんが、これが有用である場所を想像することはできます)。
最後に、答えの2番目の部分を最初の部分にリンクさせるビットです。K&R スタイルの関数定義を行う場合、関数のプロトタイプを導入するわけではありません。関数の型に関する限り、あなたの
func
の定義では
func
として
int func();
つまり、パラメータの型も総数も宣言されていないのです。元の投稿では、"...それは、それが使用するパラメータの数を指定するようです..."と述べています。形式的に言えば、そうではありません。2つのパラメータを持つK&Rスタイルの後に
func
を定義した後でも
func
として
func(1, 2, 3, 4, "Hi!");
で、その中に制約違反はないでしょう。(通常、品質の高いコンパイラは警告を出します)。
また、時々見落とされる事実として
int f()
{
return 0;
}
はまた、プロトタイプを導入しないK&Rスタイルの関数定義です。これを現代的なものにするためには、明示的に
void
をパラメータリストに入れる必要があります。
int f(void)
{
return 0;
}
最後に、よく言われることですが、K&Rスタイルの関数定義とプロトタイプでない関数宣言の両方がC99で完全にサポートされています。前者は、私の記憶が正しければ、C89/90から非推奨となっています。C99では、最初に使用する前に関数を宣言する必要がありますが、その宣言はプロトタイプである必要はありません。多くの人が関数宣言をプロトタイプと呼びますが、実際には関数宣言とプロトタイプは同じものではありません。
関連
-
ポインタ定数および定数ポインタ
-
C 言語のポインタ配列のポインタ型、ポインタに値を割り当てるために配列名を使用、コンパイル時の警告:互換性のないポインタ型からの初期化
-
C/C++の再定義
-
[解決済み] 配列の場合、なぜ a[5] == 5[a] になるのでしょうか?
-
[解決済み] Pythonの変数名や関数名の命名規則について教えてください。
-
[解決済み] 関数のソースコードを見るにはどうしたらいいですか?
-
[解決済み] printfは、フォーマット文字列の中に改行がないと、呼び出し後にフラッシュしないのはなぜですか?
-
[解決済み] char s[]とchar *sの違いは何ですか?
-
[解決済み] C言語で "unsigned long "をprintfする方法は?
-
[解決済み】JavaScriptの関数にデフォルトのパラメータ値を設定する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
コンパイルエラー:可変長オブジェクトが初期化されていない可能性があります。
-
警告: 'struct XXX' はパラメータリストの内部で宣言されています。
-
[解決済み] munmap_chunk(): 無効なポインタ
-
[解決済み] ⑭と⑯は何のためにあるのですか?
-
[解決済み] while ( !feof (file) ) 」は、なぜいつも間違っているのですか?
-
[解決済み] C言語でランダムなint型を生成するには?
-
[解決済み] printfにおけるdoubleの正しい書式指定子
-
[解決済み] char s[]とchar *sの違いは何ですか?
-
[解決済み] なぜC言語では構造体を頻繁にtypedefする必要があるのですか?
-
[解決済み] 講師が書いたC言語のファイルは、なぜ最初の行に#が一つ付いているのですか?