32

セッション記録:

> type lookma.c
int main() {
  printf("%s", "no stdio.h");
}

> cl lookma.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

lookma.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:lookma.exe
lookma.obj

> lookma
no stdio.h
4

3 に答える 3

39

あなたはもともとこの C++ にタグを付けていましたが、C プログラムのように見えます。C は、スコープ内にプロトタイプがない場合 (#include <stdio.h> の省略などにより)、関数の暗黙的な宣言を自動的に提供します。暗黙の宣言は次のようになります。

int printf();

つまり、printf は int を返し、任意の数の引数を取ることができる関数です。このプロトタイプは、たまたまあなたの電話で機能しました。#include <stdio.h> を使用する必要があります

最後に、現在の C 標準 (ISO/IEC 9899:1999 または口語的に "C99") では暗黙の宣言が許可されておら、このプログラムは準拠していないことを付け加えておきます。暗黙の宣言が削除されました。あなたのコンパイラは C99 をサポートしていないと思います。C++ も正しいプロトタイプを必要とし、暗黙的な宣言を行いません。

于 2008-12-03T11:01:25.693 に答える
33

厳密準拠モード (「理論上」を意味する) では、スコープ内の関数のプロトタイプ宣言なしで可変数の引数を取る関数を呼び出すと、未定義の動作 (これは悪いことです) が呼び出されます。printf()これは、プロトタイプ from#include <stdio.h>または同等の宣言なしで使用するプログラムで、コンパイラが好きなことを何でもできることを意味します。「好きなもの」には、オプションの 1 つとして正しく動作することが含まれます。それはあなたの例で選択されたオプションのようです。

実際には、コードは、関数の正式な宣言がなくても、ほとんどの実用的なコンパイラで問題なく動作しprintf()ます。

qrdlで指摘された通り、CコンパイラがCライブラリとリンクしているため、関数が見つかりました。

C99 と「implicit int」に関する Chris Young のコメントは正確ですが、「可変引数関数はスコープ内にプロトタイプを持たなければならない」という規則は C89 と C99 の両方に適用されることに注意してください。ほとんどのコンパイラは、デフォルトでは厳密な C99 互換モードでは動作しません。そのようにコンパイルできないコードが多すぎるためです。

クリス・ヤングは次のようにコメントしています。

明確にするために、私のコメントは暗黙の宣言を削除する C99 に関するものでした。「暗黙の int」と言うと、foo(void); などの宣言を許可する C89 の機能を参照していると思います。int foo(void); を意味する、C99 も削除されたもの。

もちろん、クリスは正しいです。C99 標準から削除された 2 つの「暗黙の宣言」機能がありました。標準の序文には、次のようにリストされています。

  • 暗黙の削除int
  • 暗黙の関数宣言を削除

私は十分に明確に考えていませんでした(したがって書いていません)。それにもかかわらず、C89 と C99 の両方で、可変数の引数を取る関数のスコープ内にプロトタイプが必要です。

説明する:

extern int pqr();
int main(void)
{
    int i = pqr(1, 3);
    return i;
}

pqr()最初の行がない場合、これは、 (指定されていない引数を使用して) 整数を返す関数として関数を暗黙的に宣言した正しい C89 フラグメントです。最初の行が で置き換えられた場合、これは整数を返す関数としてextern pqr();明示的に宣言された正しい C89 フラグメント(引数は指定されていません) ですが、戻り値の型は 'implicit ' です。書かれているように、関数は明示的に宣言され、明示的な戻り値の型がありますが、未指定の引数があります。完全に望ましいわけではありませんが、これは有効な C99 だと思います。確かに、GCC (3.4.4) はオプション ' " でそれを受け入れます。理想的には、関数宣言には完全なプロトタイプを含める必要があります。pqr()intint-std=c99 -pedanticpqr()は省略記号で定義されていましたが、そのプロトタイプは理論上必要です!)

于 2008-12-04T20:37:13.847 に答える
10

printf()は標準 C ライブラリにあり、リンカーは常に標準ライブラリを実行可能ファイルにリンクするため、標準関数が検出され、リンクの問題は発生しません。

適切なヘッダーをインクルードしないと、プロトタイプ化されていない関数が使用され、問題が発生する可能性があります。C コンパイラは、プロトタイプのない関数が返さintれ、可変数の引数を取ると想定するためです。したがって、常にヘッダーを含めてください - それはあなたの安全柵です。

于 2008-12-03T11:16:45.613 に答える