首页 > 解决方案 > 使用范围外声明

问题描述

代码:

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'
}

为什么编译器不只是给出警告use of out-of-scope declaration of 'a'

标签: cgccclang

解决方案


这是因为隐式声明函数的残留特征。如果你刚刚

void bar()
{
    b(9);    
}

这实际上是 100% 有效的准标准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给出硬错误的原因;在您的原始示例中,abar. (请注意,如果您用不同的类型重新声明它,这也会使程序的含义未定义。)


推荐阅读