web-dev-qa-db-ja.com

関数宣言:K&R対ANSI

K&R関数宣言とANSI関数宣言の違いは何ですか?

35
ashna

K&R構文は廃止されました。非常に古いコードを保守する必要がない限り、スキップできます。

// K&R syntax
int foo(a, p) 
    int a; 
    char *p; 
{ 
    return 0; 
}

// ANSI syntax
int foo(int a, char *p) 
{ 
    return 0; 
}
56
Wizard

レガシーK&Rスタイルの宣言/定義

カーニハンとリッチーが最初に「Cプログラミング言語」を公開したとき、Cはまだ完全な関数プロトタイプを提供していませんでした。関数の前方宣言が存在しましたが、戻り値の型を示すことのみを目的としています。 intを返す関数の場合、C99までは必要ありませんでした。

C89によって、パラメーターのタイプ(および暗黙的にはその数)も指定する関数プロトタイプの概念が追加されました。プロトタイプも関数宣言の一種であるため、プロトタイプではない関数宣言を非公式に「K&R関数宣言」と呼ぶことがあります。

// K&R declarations, we don't know whether these functions have parameters.
int foo(); // this declaration not strictly necessary until C99, because it returns int
float bar();

// Full prototypes, specifying the number and types of parameters
int foo(int);
float bar(int, float);

// K&R definition of a function
int foo(a)
    int a; // parameter types were declared separately
{
    // ...
    return 0;
}

// Modern definition of a function
float bar(int a, float b) 
{
    // ...
    return 0.0;
}

偶発的なK&R宣言

Cを初めて使用する人は、完全なプロトタイプを使用するつもりで誤ってK&R宣言を使用する可能性があることに注意してください。空のパラメーターリストをvoidとして指定する必要があることに気付かない可能性があるためです。

関数を次のように宣言して定義すると、

// Accidental K&R declaration
int baz(); // May be called with any possible set of parameters

// Definition
int baz() // No actual parameters means undefined behavior if called with parameters.
          // Missing "void" in the parameter list of a definition is undesirable but not
          // strictly an error, no parameters in a definition does mean no parameters;
          // still, it's better to be in the habit of consistently using "void" for empty
          // parameter lists in C, so we don't forget when writing prototypes.
{
    // ...
    return 0;
}

...その後、実際には、パラメータを取らない関数のプロトタイプを指定していませんが、不明なタイプの不明な数のパラメータを受け入れる関数のK&Rスタイルの宣言です。

AnTは this answer で同様の質問に言及していますが、この構文は非推奨ですが、C99の時点ではまだ有効です(そして、パラメーターの数とタイプが不明な関数への関数ポインターは、高いリスクはありますが、まだ潜在的なアプリケーションがあります未定義の動作);そのため、適切なプロトタイプなしで関数が宣言または呼び出された場合、準拠コンパイラはせいぜい警告を生成します。

プロトタイプなしで関数を呼び出すと、コンパイラが正しい数と型のパラメータを正しい順序で渡したことを確認できないため、安全性が低下します。呼び出しが実際に正しくない場合、未定義の動作が発生します。

もちろん、パラメーターなしの関数を宣言して定義する正しい方法は次のとおりです。

// Modern declaration of a parameterless function.
int qux(void);  // "void" as a parameter type means there are no parameters.
                // Without using "void", this would be a K&R declaration.

// Modern definition of a parameterless function
int qux(void)
{
    // ...
    return 0;
}
25

int値を返す関数の従来のK&Rスタイルのタイプ修飾子は必要ないということを追加したいだけです。

単純なHelloWorldプログラムの最新のC11表記を考えてみます。

_int main(int argc, char **argv) {
    printf("hello world\n");
    return 0;
}
_

これは、K&R表記スタイルと同等です。

_main(argc, argv)
int argc;
char **argv;
{
 printf("hello world\n");
 return 0;
}
_

main()の前のintは無視されますが、コードは引き続きコンパイルされることに注意してください。これは、K&R定義の一部です。

ウィキペディアの引用:

Cの初期のバージョンでは、int以外の値を返す関数のみを関数定義の前に使用する場合に宣言する必要がありました。以前の宣言なしで使用された関数は、その値が使用された場合、int型を返すと想定されていました。

-ソース: https://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C

これは間違いなくレガシーコーディングスタイルであり、明快さの問題のために避ける必要がありますが、古いアルゴリズムの教科書では、この種のK&Rスタイルを好むことがよくあります。

0
BearAqua