3

私は K & R から C を勉強していましたが、本書のパート 4.4 でスコープ規則について言及していて混乱しました。先に進む前に、作業中のソース ファイルを投稿させてください。

#include <stdio.h>

void first(void);

int main(void) {
    printf("In main.\n");

    first();
    second();

    return 0;
}

void first(void) {
    printf("In first.\n");
}

void second(void) {
    printf("In second.\n");
}

さて、私が想像以上に愚かでない限り、この本は、関数プロトタイプ (関数の定義と同じファイル内) がスコープ上の理由で存在するという考えを与えてくれました。つまり、コンパイルされたファイルの先頭で関数を宣言して、ソースファイルの残りの部分に「オブジェクト」の存在を事前に通知できるようにするために存在します。

上記のコードに関する私の問題はGCC version 4.7.1、上記のファイルで作業している Arch Linux 仮想マシンでコンパイルでき、次のエラーが発生することです: conflicting types for second.

ただし、GCC バージョン 4.6.3を搭載したUbuntu 12.04を搭載した物理マシンでまったく同じコードを実行すると、問題なくコンパイルされます。

私の質問は:これはコンパイラの機能ですか? そうでない場合、 の関数プロトタイプがないためsecond、 (正しく理解していれば)の存在mainを知ることができないはずなので、まったくコンパイルされないことに驚いています。second

4

1 に答える 1

5

ほとんどの C コンパイラは、まだ宣言されていない関数に遭遇すると、int を返すその関数のプロトタイプを暗黙的に宣言するため、「競合する型」エラー メッセージが表示されます。したがって、second()で が検出された場合main()、GCC 4.7.1 は次の定義を推測しています。

int second();

次に、コンパイラが関数定義に到達すると、推論されたプロトタイプのシグネチャが定義のシグネチャと一致しないことに気づき、エラーで中止されます。

4.6.3 がこのコードを正常にコンパイルする理由については、次のように推測できます。GCC 4.6.3 には、戻り値の型によって関数の実装がプロトタイプと異なる可能性があるバグ (または機能、決定する) がある可能性があります。C では、void 以外の戻り値の型を持つ関数が何も返さずに終了することが許可されているため (これにより、戻り値が未定義になります)、これは単に 2 つの準最適なものが互いに打ち消し合うケースである可能性があります。

(4.6.3 での動作は、バージョン間でデフォルトのコンパイラ オプションが変更されたか、異なるオプションでコンパイラを呼び出している可能性もあります。)

于 2012-10-09T17:06:52.887 に答える