使用范围外声明

时间:2018-08-15 01:43:36

标签: c gcc clang

代码:

FROM openjdk:8u131

...

...

CMD ["java","-XshowSettings:vm -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap","-jar", "target/my-jar.jar"]

为什么编译器不仅发出void foo() { extern int a; extern void b(int); } void bar() { b(9); // ok, warning: use of out-of-scope declaration of 'b' a=9; // error: use of undeclared identifier 'a' } 之类的警告?

1 个答案:

答案 0 :(得分:5)

这是由于隐式声明函数的残留特征所致。如果你刚刚

void bar()
{
    b(9);    
}

实际上是100%有效的 pre-standard C(嗯,除了void当时不存在,但现在不重要)等同于写作

void bar()
{
    extern int b();
    b(9);    
}

(请记住,函数声明中的空参数列表不是不是,这意味着该函数接受零个参数。这意味着该函数接受一个未指定数量的参数。)

现在,当您拥有

void foo()
{
    extern void b(int);
}

void bar()
{
    b(9);
}

隐式声明意味着您写过

void foo()
{
    extern void b(int);
}

void bar()
{
    extern int b();
    b(9);
}

外部符号b的两个声明不兼容。如果它们在bar的范围内均可见,则将违反约束条件(“ X是约束冲突”是C标准最接近说“执行X的程序无效且编译器执行的程序”必须拒绝”)。但是它们不是,所以程序的含义是不确定的。 clang似乎已决定应用foo范围内的声明,但也警告您有关此声明,这对我来说似乎很公平。 gcc确实将其视为错误:

test.c:6:5: error: incompatible implicit declaration of function ‘b’
     b(9);
     ^
test.c:2:17: note: previous implicit declaration of ‘b’ was here
     extern void b(int);
                 ^

(“先前的隐式声明”不太正确,但是现在也不重要。)

您可能会看到这种事情如何导致难以发现的错误,这就是为什么现代最佳实践是在文件范围内声明仅带有外部链接的东西并声明所有功能都带有完整的原型。

仅隐式声明了函数,这就是a产生硬错误的原因;在您的原始示例中,a对于bar是完全不可见的。 (请注意,如果您使用其他类型重新声明了它,那也将使程序的含义不确定。)