冲突类型与不兼容的隐式声明

时间:2012-08-06 08:55:36

标签: c gcc function-declaration

相关的C程序如下:

    #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'的冲突类型),为什么?

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

3 个答案:

答案 0 :(得分:1)

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

一写完

void bar(int);

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

void testifbarisvisible()
{
    bar(2);
}

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

答案 1 :(得分:0)

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

在我们的案例中,bar函数仅在main内可见,而不在函数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");
}

答案 2 :(得分:0)

在main中,bar只有功能范围;它只在主要内部知道。但是,C有另一个名为 linkage 的进程。 Per C 1999 6.2.2 1,“在不同范围或同一范围内多次声明的标识符可以通过称为链接的过程引用相同的对象或函数。”

在main中,声明void bar(int);声明具有外部链接的bar,根据C 1999 6.2.2 5:“如果函数的标识符声明没有存储类说明符,则其链接确定为如果它是使用存储类说明符extern声明的那样。“

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

删除void bar(int);时,main中没有明确的bar声明。相反,bar是由以下行bar(1);隐式声明的。这种隐式与testifbarisvisible中的隐式声明具有相同的类型。因为声明是相同的,所以没有错误。编译器仍会给出警告,因为隐式声明是危险的(因为最终的显式声明可能位于不同的文件中,可能不同,这可能会导致执行时出现未确诊的错误。)