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

Des*_*tor 21 c variables definition language-lawyer

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

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

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

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

C99 6.9.2/2

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

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

Sha*_*our 8

Tentative definitions was created as a way to bridge incompatible models that existed pre-C89. This is covered in the C99 rationale section 6.9.2 External object definitions which says:

Prior to C90, implementations varied widely with regard to forward referencing identifiers with internal linkage (see §6.2.2). The C89 committee invented the concept of tentative definition to handle this situation. A tentative definition is a declaration that may or may not act as a definition: If an actual definition is found later in the translation unit, then the tentative definition just acts as a declaration. If not, then the tentative definition acts as an actual definition. For the sake of consistency, the same rules apply to identifiers with external linkage, although they're not strictly necessary.

and section 6.2.2 from the C99 rationale says:

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

  • @PravasiMeet 我很了解它,因为我花了很多时间阅读标准和相关文档以及 SO 问题。这只是关于实践和经验。你拥有的经验越多,你解决的问题就越有趣,它只是从那里开始构建的。 (2认同)

R..*_*R.. 6

这是一个有用的案例示例:

void (*a)();

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

static void (*a)() = foo;

/* ... code that uses a ... */
Run Code Online (Sandbox Code Playgroud)

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

  • 避免这种情况的另一种方法是“void foo();” void (*a)() = foo;` (4认同)
  • 在这种特定情况下,您可以通过在第一行添加“extern”(使其只是一个声明)来避免临时声明的需要。如果您希望“a”为“static”(文件范围),则真正需要临时声明的地方 (3认同)