8

これが C で正常にコンパイルされる理由を知っている人はいますか?

int main(){
     display();
   return 0;
 } 

 void display(){
     printf("Why am I compiling successfully?");
 }

宣言が提供されていない場合、Cが想定するextern int Function_name(arg1,arg2,...){}.ため、これはエラーになるはずですが、機能していると思いました! Ideoneが警告を抑制していることは知っていますが、私の質問は、なぜそれが単純なエラーを出さないのですか? (ただし、C++ では単純なエラーです)

4

5 に答える 5

8

コンパイラで警告レベルを上げると、 2 つの警告が表示されるはずです。

display宣言されていない、int想定されている

display再宣言した

編集:

C の古いバージョン (C99 より前) では、戻り値の型や引数の型についてそれほど気にする必要はありません。K&Rの遺産の一部と言えます。たとえば、引数の型を明示的に指定しない場合、コンパイラはそれらをまったくチェックしません。

C++ はより厳密であり、IMO は良いことです。C でコーディングするときは、常に宣言を行い、常に引数リストを指定します。

于 2012-11-19T12:52:11.160 に答える
5

C は下位互換性のために多くのデフォルトを使用するため、コンパイルしています。K&R C では、関数プロトタイプを指定できなかったため、コンパイラは、関数を呼び出すときに何をしているかを知っていると想定するだけでした。

その後 (少なくとも ANSI C、しかしおそらく C99 でも)、C には実際に区別する方法がありませんでした。

void display(void);
void display();

したがって、空の宣言も受け入れる必要があります。

display()そのため、最初に定義せずに呼び出すことができます。

printf()似ている。忘れるとリンカエラーが発生します-lcが、コンパイラの観点からは、コードは「十分」です。

これは、コンパイラが提供する必要があるすべての警告を有効にするとすぐに変更され、K&C 互換性を無効にするか厳密な ANSI チェックを有効にすると、エラーで失敗します。

そのため、「プログラミング言語を使用して足を撃つ方法」の種類のリストで、「C」が「足を撃つ」とリストされることがよくあります。

于 2012-11-19T12:53:34.110 に答える
3

それはあなたのCxに依存します(C89、C90、C99、...)

関数の戻り値については、C99 より前では、関数宣言が表示されない場合はトランスレーターが提供することが明示的に指定されていました。これらの暗黙の宣言は、デフォルトで int の戻り値の型になりました

C 標準からの正当化(6.2.5 ページ 506)

C90 より前は、関数プロトタイプはありませんでした。開発者は、同じ整数型の符号付きバージョンと符号なしバージョンを持つ引数を交換できることを期待していました。関数定義のパラメータ型の符号が異なる場合に引数をキャストしなければならないことは、C の簡単な型チェック システムに反するものであり、少し煩わしいものと見なされていました。プロトタイプの導入によって、引数の互換性の問題が完全に解消されたわけではありません。省略記号表記は、1590 省略記号について何も知られていないことを指定します。省略記号は、引数の期待されるタイプの情報を提供しません。同様に、関数の戻り値の場合、C99 より前では、関数宣言が表示されない場合はトランスレーターが提供することが明示的に指定されていました。これらの暗黙の宣言は、デフォルトで int の戻り値の型になりました。実際の関数がたまたま型 unsigned int を返す場合、そのようなデフォルト宣言は予期しない結果を返す可能性があります。多くの開発者は、関数宣言に対してカジュアルな態度をとっていました。私たちの残りの部分は、委員会が書いたすべてのソースコードを壊したくないという結果を受け入れなければなりません. C99 では関数宣言が呼び出し時に可視である必要があるため、関数の戻り値の交換可能性は現在問題になっています (既定の宣言は提供されなくなりました)。

于 2012-11-19T13:13:29.137 に答える
1

おそらくそうです(あなたが書いたような宣言を想定しています)が、パラメーターを渡していないので、うまく機能します。int main()実際にどこにあるべきかを宣言するのと同じですint main(int argc, char *argv[])

したがって、おそらく、いくつかのパラメーター(デフォルトのパラメーターとは異なる)を渡そうとした場合、mainそれらを使用するdisplayと失敗します。

ところで、私にとってはコンパイルされますが、警告が生成されます:

$ gcc z.c
z.c:8:6: warning: conflicting types for ‘display’ [enabled by default]
z.c:4:5: note: previous implicit declaration of ‘display’ was here
于 2012-11-19T12:57:12.677 に答える
0

gcc でコンパイルすると、ご想像のとおり、 の再宣言に関する警告が表示displayされます。

警告を受けましたか?

C は (C++ のように) 関数名をマングルしないため、「実行」される可能性があります。そのため、リンカーはシンボル「display」を探して見つけます。リンカーは、このアドレスを使用してdisplay. 私は結果が常にあなたが期待するものではないことを期待しています.

于 2012-11-19T12:54:45.333 に答える