1

関連する C プログラムは次のとおりです:</p>

    #include <stdio.h>

    void testifbarisvisible();

    int main()
    {
            void bar(int);
        bar(1);
        testifbarisvisible();
    }

    void testifbarisvisible()
    {
        bar(2);
    }

    void bar(int x)
    {
        printf("functionbar\n");
    }

gcc の出力は次のとおりです。

% gcc -std=c99 -c /tmp/notfilescope.c
/tmp/notfilescope.c: In function ‘testifbarisvisible’:
/tmp/notfilescope.c:14:2: warning: implicit declaration of function ‘bar’
/tmp/notfilescope.c:7:7: note: previous declaration of ‘bar’ was here
/tmp/notfilescope.c:14:2: error: incompatible implicit declaration of function ‘bar’
/tmp/notfilescope.c:7:7: note: previous implicit declaration of ‘bar’ was here

7 行目のステートメントを削除すると、出力は次のようになります。

% gcc -std=c99 -c /tmp/notfilescope.c
/tmp/notfilescope.c: In function ‘main’:
/tmp/notfilescope.c:8:2: warning: implicit declaration of function ‘bar’
/tmp/notfilescope.c: At top level:
/tmp/notfilescope.c:17:6: warning: conflicting types for ‘bar’
/tmp/notfilescope.c:8:2: note: previous implicit declaration of ‘bar’ was here

gcc のバージョンは次のとおりです。

% gcc --version
gcc (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2)
Copyright (C) 2011 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE

gcc の 2 つの出力の違いについて混乱しています。

これは gcc のドキュメントからのものです。「ブロック内の外部変数と関数の宣言は、宣言を含むブロックにのみ適用されます。つまり、同じ場所にある他の宣言と同じスコープを持ちます。」

したがって、7 行目の関数宣言は 14 行目の関数呼び出しとは関係がないと思います。しかし、結果は意見が間違っていることを示しています。それらはすべて関数 'bar' の暗黙的な宣言ですが、そのうちの 1 つはエラー (関数 'bar' の互換性のない暗黙的な宣言) につながり、もう 1 つは警告 ('bar' の競合する型) につながります。

この質問は私を長い間混乱させてきました。誰かが私を助けることができますか?

4

3 に答える 3

1

得られる結果は合理的だと思います。

書いたらすぐ

void bar(int);

このコンパイル単位のどこかにその署名を持つ関数があることを宣言していますが、これは暗黙の宣言ではなく、どちらかといえば明示的です。ただし、ドキュメントに記載されているように、この宣言はそれが含まれているスコープをエスケープしないため、

void testifbarisvisible()
{
    bar(2);
}

そのような宣言はスコープ内になく、コンパイラは文句を言います。

于 2012-08-06T09:17:58.270 に答える
0

main 内では、bar は関数スコープのみを持ちます。メイン内でのみ認識されます。ただし、C には、リンケージと呼ばれる別のプロセスがあります。C 1999 6.2.2 1 によると、「異なるスコープまたは同じスコープで複数回宣言された識別子は、リンケージと呼ばれるプロセスによって同じオブジェクトまたは関数を参照することができます。」</p>

main では、void bar(int);C 1999 6.2.2 5 に従って、宣言は外部リンケージを使用して bar を宣言します。クラス指定子 extern.」</p>

次に、testifbarisvisible では、bar はスコープ外です。このステートメントbar(2);は、bar を外部として暗黙的に宣言します。また、bar はスコープ内にないため、プロトタイプのない bar の暗黙的な宣言になります。この暗黙の宣言は、前の とは異なる型を持っていますvoid bar(int);が、リンケージのため、同じ関数を参照する必要があります。(6.2.2 2 によると、「プログラム全体で、外部リンケージを持つ特定の識別子の各宣言は、同じオブジェクトまたは関数を示します。」) これは競合であるため、コンパイラはエラーを生成します。

を削除するvoid bar(int);と、メインに bar の明示的な宣言がありません。代わりに、bar は次の行によって暗黙的に宣言されますbar(1);。この暗黙の型は、testifbarisvisible の暗黙の宣言と同じ型です。宣言が同一であるため、エラーはありません。暗黙の宣言は危険であるため、コンパイラは引き続き警告を出します (最終的な明示的な宣言が別のファイルにある可能性があり、実行時に未診断のエラーが発生する可能性があるため)。

于 2012-08-06T10:02:03.270 に答える
0

コードの問題は、別の関数内で関数プロトタイプを宣言すると、この関数からのみ呼び出したいことを意味することです(関数は外部に表示されません)。

main私たちの場合、 bar 関数は functionではなく内部でのみ表示testifbarisvisibleされます。すべてのプログラムで表示できるようにするには、宣言を外部 (グローバル変数を宣言する方法と同様) またはヘッダー ファイルで行う必要があります。

#include <stdio.h>

void testifbarisvisible();

int main()
{
    void bar(int);  // bar can be use inside main, not outside
    bar(1);
    testifbarisvisible();
}

void testifbarisvisible()
{
    // void bar(int); // If you want to use it inside testifbarisvisible
    bar(2);
}

void bar(int x)
{
    printf("functionbar\n");
}
于 2012-08-06T09:39:23.223 に答える