考虑以下计划。这会给出任何编译错误吗?
#include <stdio.h>
int s=5;
int s;
int main(void)
{
printf("%d",s);
}
乍一看似乎编译器会给出变量重定义错误,但程序根据C标准完全有效。 (请参见此处的实时演示http://ideone.com/Xyo5SY)。
暂定定义是没有存储类说明符且没有初始化程序的任何外部数据声明。
C99 6.9.2 / 2
对于没有文件范围的对象的标识符声明 初始化程序,没有存储类规范或与 存储级特定的静态,构成了一个暂定的定义。如果一个 翻译单元包含一个或多个暂定定义 标识符,翻译单元不包含外部定义 那个标识符,那么行为就像翻译一样 unit包含该标识符的文件范围声明 复合类型作为翻译单元的末尾,带有 初始值设定项等于0.
我的问题是,允许暂定定义的理由是什么?在C中有没有用过这个?为什么C允许暂定定义?
答案 0 :(得分:7)
创建了暂定定义,作为桥接C89之前存在的不兼容模型的一种方法。 C99 rationale部分6.9.2
外部对象定义中介绍了这一点:
来自C99理由的在C90之前,实施方面在前进方面差异很大 引用具有内部链接的标识符(参见§6.2.2)。 C89 委员会发明了暂定定义的概念来处理这个问题 情况。暂定定义是可能会或可能不会的声明 充当定义:如果在后面找到实际定义 翻译单位,然后暂定的定义只是作为一个 宣言。如果没有,那么暂定的定义就像一个实际的定义 定义。为了保持一致性,适用相同的规则 具有外部联系的标识符,尽管它们并不严格 必要的。
和6.2.2
部分说:
用于具有外部链接的对象的定义模型是 一个主要的C89标准化问题。基本问题是决定 对象的声明定义对象的存储,以及 它仅仅引用了现有的对象。一个相关的问题是 是否允许多个存储定义,或者只允许一个 可以接受的。 预C89实施至少展示了四种不同 模型,按照限制性增加的顺序列出:
答案 1 :(得分:4)
以下是一个有用的案例:
void (*a)();
void bar();
void foo()
{
a = bar;
}
static void (*a)() = foo;
/* ... code that uses a ... */
关键是foo
的定义必须引用a
,a
的定义必须引用foo
。具有初始化结构的类似示例也应该是可能的。