C中暂定定义背后的基本原理是什么?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C中暂定定义背后的基本原理是什么?相关的知识,希望对你有一定的参考价值。

考虑以下程序。这会给出任何编译错误吗?

#include <stdio.h>
int s=5;
int s;
int main(void)
{
     printf("%d",s);
}

乍一看似乎编译器会给出变量重定义错误,但程序根据C标准完全有效。 (参见http://ideone.com/Xyo5SY的现场演示)。

暂定定义是没有存储类说明符且没有初始化程序的任何外部数据声明。

Tsa / a公寓

对于具有文件范围而没有初始化程序且没有存储类指定程序或存储类指定程序静态的对象的标识声明构成了一个暂定的定义。如果翻译单元包含一个或多个用于标识符的暂定定义,并且翻译单元不包含该标识符的外部定义,则该行为就像翻译单元包含该标识符的文件范围声明一样,其复合类型为翻译单元的结尾,初始化程序等于0。

我的问题是,允许暂定定义的理由是什么?在C中有没有用过这个?为什么C允许暂定?

答案

创建了暂定定义,作为桥接C89之前存在的不兼容模型的一种方法。这在C99 rationale部分6.9.2外部对象定义中有所描述:

在C90之前,对于具有内部链接的前向引用标识符,实现方式差异很大(参见§6.2.2)。 C89委员会发明了暂定定义的概念来处理这种情况。暂定定义是一种可能或可能不作为定义的声明:如果稍后在翻译单元中找到实际定义,则暂定定义仅作为声明。如果没有,则暂定定义作为实际定义。为了保持一致性,相同的规则适用于具有外部链接的标识符,尽管它们并非绝对必要。

来自C99理论的部分6.2.2说:

用于具有外部链接的对象的定义模型是C89的主要标准化问题。基本问题是决定对象的哪些声明为对象定义存储,哪些只引用现有对象。一个相关的问题是,是否允许存储的多个定义,或者只有一个是可接受的。 Pre-C89实现至少展示了四种不同的模型,这些模型按照限制性增加的顺序列出:

另一答案

这是一个有用的案例:

void (*a)();

void bar();
void foo()
{
    a = bar;
}

static void (*a)() = foo;

/* ... code that uses a ... */

关键点在于foo的定义必须引用a,而a的定义必须指foo。具有初始化结构的类似示例也应该是可能的。

以上是关于C中暂定定义背后的基本原理是什么?的主要内容,如果未能解决你的问题,请参考以下文章

typedef vs struct/union/enum 背后的基本原理是啥,难道不能只有一个命名空间吗?

Apple 检查返回值而不是错误的模式背后的基本原理是啥?

AngularJS 中属性规范化背后的基本原理

静态常量(非整数)成员初始化语法背后的基本原理?

@lombok注解背后的原理是什么,让我们走近自定义Java注解处理器

前端精选文摘:BFC 神奇背后的原理