【问题标题】:use of out-of-scope declaration使用范围外声明
【发布时间】:2018-08-15 01:43:35
【问题描述】:

代码:

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' 这样的警告?

【问题讨论】:

  • @M.M 那么声明在哪里?
  • @M.M:根据b 是否在foo 中声明,godbolt.com 上的测试会给出不同的消息。我怀疑 OP 看到的消息的特定原因是函数标识符始终引用模块中的相同函数,因此 bar 中的 b 必须 引用相同的 bfoo 中,但其声明超出范围,而a 可以引用不同的对象。
  • @EricPostpischil 你是对的 - 我认为 bfoo 中的声明如果它没有被实际调用并不重要,因为声明超出了范围,但事实上这很重要

标签: c gcc clang


【解决方案1】:

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

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 完全不可见。 (注意,如果你用不同的类型重新声明了它,那也会使程序的含义不确定。)

【讨论】:

  • 谢谢,gcc 的诊断信息对我来说似乎更清楚了。
  • godbolt.com 上的测试会根据b 是否在foo 中声明而给出不同的消息。我怀疑 OP 看到的消息的特定原因是函数标识符始终引用模块中的相同函数,因此 bar 中的 b 必须 引用相同的 bfoo 中,但其声明超出范围,而a 可以引用不同的对象。
猜你喜欢
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 1970-01-01
  • 2020-04-10
  • 2015-02-08
  • 1970-01-01
相关资源
最近更新 更多