6

最初にヘッダー ファイルをインクルードしなかった場合、コンパイラは sleep 関数や printf 関数のプロトタイプをどのように認識しますか?

さらに、sleep(1,1,"xyz")または任意の数の引数を指定した場合でも、コンパイラはそれをコンパイルします。sleep()しかし、奇妙なことは、gcc がリンク時にこの関数の定義を見つけることができるということです。実際の関数は単一の引数しかとらないため、これがどのように可能であるかがわかりませんが、プログラムでは 3 つの引数が言及されています。

/********************************/
int main()
{
 short int i;
 for(i = 0; i<5; i++)
 {
    printf("%d",i);`print("code sample");`
    sleep(1);
 }
 return 0;
}
4

7 に答える 7

10

より具体的なプロトタイプがないため、コンパイラーは、関数がintを返し、指定された数の引数を取ると想定します。

CPUアーキテクチャに応じて、引数をレジスタ(たとえば、MIPSのa0からa3)で渡すか、元のx86呼び出し規約のようにスタックにプッシュすることができます。どちらの場合でも、余分な引数を渡すことは無害です。呼び出された関数は、渡されたレジスタを使用せず、スタック上の追加の引数を参照しませんが、悪いことは何も起こりません。

より少ない引数を渡すことはより問題があります。呼び出された関数は、適切なレジスタまたはスタックの場所にあるガベージを使用し、hijinksが発生する可能性があります。

于 2008-09-16T02:34:28.230 に答える
5

従来のCでは、関数を呼び出すためのプロトタイプは必要ありません。コンパイラーは、関数がintを返し、不明な数のパラメーターを受け取ると推測します。これは一部のアーキテクチャで機能する可能性がありますが、関数が構造体などのint以外のものを返す場合、またはパラメータ変換がある場合は失敗します。

あなたの例では、睡眠が見られ、コンパイラは次のようなプロトタイプを想定しています

int sleep();

引数リストが空であることに注意してください。Cでは、これはvoidと同じではありません。これは実際には「不明」を意味します。K&R Cコードを記述している場合、次のようなコードを介して未知のパラメーターを持つ可能性があります。

int sleep(t)
int t;
{
   /* do something with t */
}

これはすべて危険です。特に、プロトタイプ化されていない関数のパラメーターが渡される方法がプロトタイプの関数とは異なる一部の組み込みチップでは危険です。

注:リンクにプロトタイプは必要ありません。通常、リンカはLinux上のglibcのようなCランタイムライブラリと自動的にリンクします。スリープの使用とそれを実装するコードとの関連付けは、ソースコードが処理されてからかなり後のリンク時に発生します。

このような問題を回避するために、コンパイラの機能を使用してプロトタイプを要求することをお勧めします。GCCでは、これは-Wstrict-prototypesコマンドライン引数です。CodeWarriorツールでは、C /C++コンパイラパネルの「プロトタイプが必要」フラグでした。

于 2008-09-16T03:23:03.370 に答える
2

これは、「K&RC」および「ANSIC」と呼ばれるものと関係があります。古き良きK&RCでは、何かが宣言されていない場合、それはintであると見なされます。したがって、関数呼び出しのように見えるが、関数として宣言されていないものは、実際の呼び出しに応じて、「int」の戻り値と引数タイプを自動的に受け取ります。

しかし、人々は後でこれが時々非常に悪いことがあることに気づきました。そのため、いくつかのコンパイラが警告を追加しました。C++でこのエラーが発生しました。gccにはフラグ(-ansicまたは-pedantic?)があり、この状態をエラーにしていると思います。

つまり、一言で言えば、これは歴史的な荷物です。

于 2008-09-16T03:56:12.480 に答える
2

他の回答は、考えられるメカニズムをカバーしています(コンパイラが指定されていないため、すべての推測)。

問題は、コンパイラとリンカーがすべてのエラーと警告を有効にするように設定されていないことです。新しいプロジェクトでは、そうしないことの言い訳は (事実上) ありません。 レガシー プロジェクトの場合はより多くの言い訳が必要ですが、できるだけ多くのプロジェクトを有効にするよう努力する必要があります

于 2008-09-16T12:31:34.457 に答える
2

C は未知の型に対して int を推測します。したがって、sleep には次のプロトタイプがあると思われます。

int sleep(int);

複数のパラメーターを指定してリンクすることについては...よくわかりません。それは私を驚かせます。それが本当に機能した場合、実行時に何が起こったのでしょうか?

于 2008-09-16T02:22:05.640 に答える
1

おもちゃ以外の例では、別のファイルに見逃したファイルが含まれている場合があります。プリプロセッサからの出力を確認することは、コンパイルの結果を確認するための優れた方法です。

于 2008-09-16T03:25:33.380 に答える
1

コンパイラによって異なりますが、gcc では (たとえば、参照したものなので)、一部の標準 (C と POSIX の両方) 関数には組み込みの「コンパイラ組み込み関数」があります。これは、コンパイラに同梱されているコンパイラ ライブラリ (この場合は libgcc) に関数の実装が含まれていることを意味します。コンパイラは暗黙的な宣言 (つまり、ヘッダーなしで関数を使用する) を許可し、コンパイラをリンカ フロントエンドとして使用している可能性があるため、リンカはコンパイラ ライブラリで実装を検出します。

オブジェクトを「-c」フラグ (コンパイルのみ、リンクなし) でコンパイルしてから、リンカーを使用して直接リンクしてみてください。期待どおりのリンカ エラーが発生することがわかります。

-fno-builtinあるいは、gcc は組み込み関数の使用を無効にするオプションをサポートしています-fno-builtin-function。自作カーネルやその他の種類のオンザメタル アプリの構築などを行っている場合に役立つオプションがさらにあります。

于 2008-09-16T02:24:25.667 に答える