c - 使用范围外声明
问题描述
代码:
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'
?
解决方案
这是因为隐式声明函数的残留特征。如果你刚刚
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
给出硬错误的原因;在您的原始示例中,a
对bar
. (请注意,如果您用不同的类型重新声明它,这也会使程序的含义未定义。)
推荐阅读
- python - Pandas groupby 列是否相同或不同
- c# - SET IDENTITY_INSERT TableName ON 在 Entity Framework Core 2.2 上不起作用
- azure-active-directory - 确保新注册成员使用唯一名称
- prolog - 将元素增量添加到变量
- c# - 在使用条件测试后仍会评估空值
- python-3.x - 根据烧瓶中的其他选择选项显示选择字段
- amazon-web-services - 使用dynamoDB流触发理解同步调用的Lambda函数
- python - Python - “追加(列表)”和“追加(列表[:])”有什么不同?
- azure-ad-b2c - 自定义策略中的 Azure B2C MFA 电话因素验证重试处理
- c# - 没有 BeginLifeTimeScope 的 Autofac InstancePerLifeTimeScope