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 的两个输出之间的区别感到困惑。

这来自 gcc 的文档,“块内外部变量和函数的声明仅适用于包含声明的块。换句话说,它们与同一位置的任何其他声明具有相同的范围。”

所以我认为第 7 行的函数声明与第 14 行的函数调用没有关系。但结果表明观点是错误的。它们都是函数'bar'的隐式声明,但其中一个导致错误(函数'bar'的隐式声明不兼容),另一个导致警告('bar'的类型冲突),为什么?

这个问题让我困惑了很久。有人能帮我吗?

4

3 回答 3

1

我会说你得到的结果是合理的。

只要你写

void bar(int);

你声明在这个编译单元的某个地方有一个带有该签名的函数,这不是一个隐式声明,它是显式的,如果有的话。但是,正如文档所指出的,这个声明并没有逃脱它所在的范围,所以当你到达

void testifbarisvisible()
{
    bar(2);
}

没有这样的声明在范围内,编译器会抱怨。

于 2012-08-06T09:17:58.270 回答
0

你的代码的问题是,当你在另一个函数中声明一个函数原型时,这意味着你只想从这个函数调用它(这个函数在外面是不可见的)。

在我们的例子中, bar 函数只在 inside 可见main,而不是在 functiontestifbarisvisible中可见,为了使其对所有程序可见,必须在外部(如声明全局变量的方式)或在头文件中进行声明。

#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 回答
0

在 main 中,bar 只有函数作用域;它只在 main 中知道。但是,C 有另一个称为链接的过程。根据 C 1999 6.2.2 1,“在不同范围或同一范围内多次声明的标识符可以通过称为链接的进程引用同一对象或函数。”</p>

在 main 中,声明void bar(int);声明了带有外部链接的 bar,根据 C 1999 6.2.2 5:“如果函数标识符的声明没有存储类说明符,则它的链接被确定为就好像它是用存储类声明的一样。类说明符 extern。”</p>

然后,在 testifbarisvisible 中, bar 不在范围内。该语句bar(2);隐式声明 bar 是外部的,并且因为 bar 不在范围内,所以它是 bar 的隐式声明,没有原型。这个隐式声明的类型与前一个不同void bar(int);,但由于链接,它必须引用相同的函数。(根据 6.2.2 2,“在……整个程序中,具有外部链接的特定标识符的每个声明都表示相同的对象或函数。”)这是一个冲突,因此编译器会产生错误。

When you remove void bar(int);, there is no explicit declaration of bar in main. Instead, bar is implicitly declaration by the following line, bar(1);. This implicit has the same type as the implicit declaration in testifbarisvisible. Because the declarations are identical, there is no error. The compiler still gives you a warning because implicit declarations are dangerous (because the eventual explicit declaration might be in a different file and might be different, which can cause undiagnosed errors at execution).

于 2012-08-06T10:02:03.270 回答